![GetX & Flutter: UDF with Rx-variables GetX & Flutter: UDF with Rx-variables](https://habrastorage.org/getpro/habr/upload_files/1ce/aeb/d16/1ceaebd1647c779689f9105c35dc05ed.png)
Замечание: Почему скриншоты вместо сниппетов кода? Просто красивее выглядит. Весь упоминаемый код находится на Github gist, а сама библиотека на pub.dev.
Reactive State Management в GetX сделан очень изящно и реализуется буквально в пару строк - одна в контроллере и одна во View, как-то так
![](https://habrastorage.org/getpro/habr/upload_files/1a9/69f/3b9/1a969f3b9107ff9f7636e2255fc42111.png)
Однако есть проблема. Этот подход нарушает принцип UDF, да в общем-то и все наперечет архитектурные паттерны приложений MVC/MVVM и далее по порядку в части взаимодействия View с состоянием модели. View не должна иметь возможность напрямую изменять это состояние. А в примере выше именно так и происходит.
![](https://habrastorage.org/getpro/habr/upload_files/98a/b96/84b/98ab9684bcfa4bd14c81603ac3af8ab6.png)
Модель никак не модерирует состояние, View его изменила и тут же получила обратно. В данной реализации с этим ничего не поделать, так как переменная clickCounter
публична.
Конечно, в GetX как всегда находится решение, и оно достаточно простое - спрятать переменную за геттером и сеттером:
![](https://habrastorage.org/getpro/habr/upload_files/892/a50/970/892a5097064e23f213d7db1484775123.png)
В этом случае принцип UDF восстановлен, мы имеем возможность управлять бизнес-логикой, прежде чем View получит результат.
![](https://habrastorage.org/getpro/habr/upload_files/c60/826/ca3/c60826ca3e26b8bb8e25908af0db752c.png)
В общем-то, на этом можно и остановиться, решение рабочее. Но...
Переменная разрослась до трех сущностей. А если кроме этого потребуется обращаться к ее стриму, то придется добавить еще и его:
![](https://habrastorage.org/getpro/habr/upload_files/6ac/7ea/1e7/6ac7ea1e7816185cba11bcae5b140664.png)
Управлять 3-4 сущностями для каждой переменной то еще занятие. Многословно, чревато ошибками, не изящно.
Все эти вопросы (и не только) призван решить GetRxDecorator
.
GetRxDecorator как элегантный путь к UDF
Вместо четырех переменных как описано выше, можно написать что-то вроде этого
![](https://habrastorage.org/getpro/habr/upload_files/09d/3a4/ba0/09d3a4ba051f696ab7f51c599bc21a4b.png)
Мы заменяем 4 переменные на одну, инкапсулируя поведение в стиле ООП & UDF, исключая непреднамеренное нарушение доступа к изменению напрямую.
Этот подход реализует паттерн Decorator
вокруг Rx-переменной. В самом простом случае достаточно написать var rxVarInt = 1.obsDeco()
вместо var rxVarInt = 1.obs
.
Дополнительные возможности декоратора
Опциональный параметр
args
в сеттере и его колбеке
Он позволяет реализовывать нестандартную логику присвоения в определенных случаях.
К примеру, когда изменение значения происходит только в случае если аргумент либо не тип Int
, либо значение агрумента больше 1, то сеттер выглядит как-то так
![](https://habrastorage.org/getpro/habr/upload_files/dae/c96/79c/daec9679ca21622e6a51773612792663.png)
а по тестам видно, что присвоение происходит верно
![](https://habrastorage.org/getpro/habr/upload_files/ced/add/a26/cedadda26dbb502c5667835585d87638.png)
Параметр
oldValue
в колбеке сеттера
В колбек сеттера передается текущее значение переменной через параметр oldValue
. Используя его вместо (вместе) newValue
можно реализовывать необычные алгоритмы, основанные на текущем значении переменной, типа "Гипотезы Коллатца". Это может выглядеть как-то так:
![](https://habrastorage.org/getpro/habr/upload_files/175/bca/3fc/175bca3fc9a755b7a9d8d0cd2ffff1be.png)
(См. в тесте ‘Collatz conjecture setter test’ и в примере в библиотеке)
Опциональный параметр
forceRefresh
.
Этот параметр позволяет форсировать обновление неизмененной переменной.
![](https://habrastorage.org/getpro/habr/upload_files/7f9/106/6bb/7f91066bb9d03c6a8d3cefe2c6bcfeed.png)
Исходники и библиотека
Исходники можно посмотреть на GitHub gist
Так же решение оформлено, как часть библиотеки на pub.dev