GetX & Flutter: UDF with Rx-variables

Замечание: Почему скриншоты вместо сниппетов кода? Просто красивее выглядит. Весь упоминаемый код находится на Github gist, а сама библиотека на pub.dev.

Reactive State Management в GetX сделан очень изящно и реализуется буквально в пару строк - одна в контроллере и одна во View, как-то так

Однако есть проблема. Этот подход нарушает принцип UDF, да в общем-то и все наперечет архитектурные паттерны приложений MVC/MVVM и далее по порядку в части взаимодействия View с состоянием модели. View не должна иметь возможность напрямую изменять это состояние. А в примере выше именно так и происходит.

Модель никак не модерирует состояние, View его изменила и тут же получила обратно. В данной реализации с этим ничего не поделать, так как переменная clickCounter публична.

Конечно, в GetX как всегда находится решение, и оно достаточно простое - спрятать переменную за геттером и сеттером:

В этом случае принцип UDF восстановлен, мы имеем возможность управлять бизнес-логикой, прежде чем View получит результат. 

В общем-то, на этом можно и остановиться, решение рабочее. Но...

Переменная разрослась до трех сущностей. А если кроме этого потребуется обращаться к ее стриму, то придется добавить еще и его:

Управлять 3-4 сущностями для каждой переменной то еще занятие. Многословно, чревато ошибками, не изящно.

Все эти вопросы (и не только) призван решить GetRxDecorator.

GetRxDecorator как элегантный путь к UDF

Вместо четырех переменных как описано выше, можно написать что-то вроде этого

Мы заменяем 4 переменные на одну, инкапсулируя поведение в стиле ООП & UDF, исключая непреднамеренное нарушение доступа к изменению напрямую.

Этот подход реализует паттерн Decorator вокруг Rx-переменной. В самом простом случае достаточно написать var rxVarInt = 1.obsDeco() вместо var rxVarInt = 1.obs.

Дополнительные возможности декоратора

  1. Опциональный параметр args в сеттере и его колбеке

Он позволяет реализовывать нестандартную логику присвоения в определенных случаях.

К примеру, когда изменение значения происходит только в случае если аргумент либо не тип Int, либо значение агрумента больше 1, то сеттер выглядит как-то так

а по тестам видно, что присвоение происходит верно

  1. Параметр oldValue в колбеке сеттера

В колбек сеттера передается текущее значение переменной через параметр oldValue. Используя его вместо (вместе) newValue можно реализовывать необычные алгоритмы, основанные на текущем значении переменной, типа "Гипотезы Коллатца". Это может выглядеть как-то так:

(См. в тесте ‘Collatz conjecture setter test’ и в примере в библиотеке)

  1. Опциональный параметр forceRefresh.

Этот параметр позволяет форсировать обновление неизмененной переменной.

Исходники и библиотека

Исходники можно посмотреть на GitHub gist

Так же решение оформлено, как часть библиотеки на pub.dev