В качестве продолжения к предыдущей статье об общем состоянии для компонентов, дальше развиваю тему и хочу реализовать фичу, которая позволит отлавливать и обрабатывать в каждом компоненте событие по изменению состояния (когда данные в общем состоянии изменяются в каком-то компоненте).
Ссылка на проект
Обычно для того, чтобы отследить изменение данных, в каком то компоненте, создается прямая связь, то есть мы, либо в методе Update проверяем, не изменились ли там данные
![](https://habrastorage.org/webt/-1/gf/ku/-1gfkucrj5abburhxd_vtvqagki.png)
Пофреймовая проверка данных через метод Update
либо подписываемся на вполне конкретное событие, которое вызывается самостоятельно в «отслеживаемом» компоненте, и в конечном потом обрабатывается.
![](https://habrastorage.org/webt/e4/mn/q-/e4mnq-sccgk2wlges6ovwizufwu.png)
Подписка на событие в компоненте и обработка его
Есть множество недостатков в таком подходе, которые по большей части описаны в прошлой статье. Главная общая причина этих недостатков это сильная связанность и сложная maintenance (способность поддерживать, развивать проект, рефакторить).
Теперь когда имеется система, позволяющая ослабить связь между компонентами и средства для создания рассылок между компонентами, можно избавиться от ручной проверки значений в общем состоянии, следующим образом:
![](https://habrastorage.org/webt/7w/s8/va/7ws8vae6-qqmrpm_l_9wqjbta1a.png)
Схема уведомления об изменении общего состояния
В реализации, описанной в предыдущей статье, данные изменяются в одном месте, в индексаторе компонента SharedState и поэтому контролировать их изменение очень просто
![](https://habrastorage.org/webt/uy/zv/xb/uyzvxbhx-nepvv1giwrkd7pxaeu.jpeg)
Индексатор в общем состоянии
В сеттере индексатора мы присваиваем значения состояния.
Теперь для SharedState компонента нужно добавить зависимость от SharedEvents, так как именно его и буду использовать для отправки уведомлений. Добавим атрибут для SharedState
![](https://habrastorage.org/webt/_7/l1/-n/_7l1-nuhqo6ylipqxgpsvotn8bw.jpeg)
Добавление зависимости в SharedState от SharedEvents
И создам класс, наследуемый от EventData, для отправки данных в уведомлении об изменении состояния. Он будет содержать название параметра, в состоянии и его новое значение
![](https://habrastorage.org/webt/_i/20/nz/_i20nz08kpnahewfnh3dbyxy2d4.jpeg)
Добавление класса, который содержит информацию об изменении в общем состоянии
Теперь нужно добавить ссылку на SharedEvents, получив ее из игрового объекта в компоненте SharedState
![](https://habrastorage.org/webt/r8/tq/kt/r8tqktsica48---wrqvsy_d0ho8.jpeg)
Получение SharedEvents в компоненте SharedState
Теперь изменим сеттер индексатора таким образом, чтобы при каждом изменении состояния создавалось уведомление с именем «sharedstatechanged» и передадим объект, содержащий все данные об изменении
![](https://habrastorage.org/webt/xp/dn/ck/xpdnckwptsg7xwwmpqjcmplzx9c.jpeg)
Изменение сеттера индексатора
Теперь осталось подписаться на изменения в каком либо компоненте, изменить данные в другом и проверить как это работает.
Допустим SecondComponent меняет состояние, например параметр «somedata», а компонент FirstComponent отслеживает изменение состояния, подписавшись на уведомления
В SecondComponent вызовем изменение параметра
![](https://habrastorage.org/webt/fp/uo/u3/fpuou3efwyrujfdxgia1dufdvii.jpeg)
Вызов изменения данных
И теперь в методе FirstComponent добавляем обработчик и выводим в консоль информацию об изменении общего состояния
![](https://habrastorage.org/webt/4i/js/kd/4ijskdeiwopjqe_tevz1dx7rgsg.jpeg)
Обработка события об изменении общего состояния
Теперь если запустить игру, после того как общее состояние будет изменено в SecondComponent, в компоненте FirstComponent мы получим уведомление и выведем данные в консоль
![](https://habrastorage.org/webt/sb/v9/09/sbv909u0qrag-xdvsho9xgcnfua.jpeg)
Теперь, когда это работает, можно немного отрефакторить и сделать код еще более удобным. Для этого нужно перенести подписку на уведомления об изменении общего состояния в базовый класс SharedStateComponent и создать абстрактный метод, реализовав который каждый компонент будет обрабатывать в нем изменения состояния, или нет, на усмотрение компонента.
Переносим подписку в SharedStateComponent
![](https://habrastorage.org/webt/wm/ja/v8/wmjav8ntn-fmjnlmfpzzgoy4gmm.jpeg)
Подписка на уведомления об изменении общего состояния в базовом классе
Добавляем абстрактный метод и вызываем его в обработчике события
![](https://habrastorage.org/webt/m8/_c/fd/m8_cfdykkvyyhuryvwxh7be6s8a.jpeg)
Добавление абстрактного метода, для обработки события в дочерних классах
И теперь в каждом дочернем компоненте FirstComponent и SecondComponent нужно реализовать этот метод и обработать в нем изменение общего состояния. Но мы как и прежде просто выведем это в консоль
![](https://habrastorage.org/webt/qr/ef/pl/qrefplcb2ee40ldokajn5iybrt8.jpeg)
Имплементация абстрактного метода в компонентах FirstComponent и SecondComponent
И теперь когда мы запустим игру мы увидим 2 записи в консоли, из обоих компонентов.
![](https://habrastorage.org/webt/zo/ts/_l/zots_l96h0b7kawbgjgq6pnouco.jpeg)
В предыдущей реализации был баг в классе SharedEvents и чтобы его пофиксить нужно изменить метод Subscribe на:
Ссылка на проект
Обычно для того, чтобы отследить изменение данных, в каком то компоненте, создается прямая связь, то есть мы, либо в методе Update проверяем, не изменились ли там данные
![](https://habrastorage.org/webt/-1/gf/ku/-1gfkucrj5abburhxd_vtvqagki.png)
Пофреймовая проверка данных через метод Update
либо подписываемся на вполне конкретное событие, которое вызывается самостоятельно в «отслеживаемом» компоненте, и в конечном потом обрабатывается.
![](https://habrastorage.org/webt/e4/mn/q-/e4mnq-sccgk2wlges6ovwizufwu.png)
Подписка на событие в компоненте и обработка его
Есть множество недостатков в таком подходе, которые по большей части описаны в прошлой статье. Главная общая причина этих недостатков это сильная связанность и сложная maintenance (способность поддерживать, развивать проект, рефакторить).
Создание решения «Уведомления об изменении состояния»
Теперь когда имеется система, позволяющая ослабить связь между компонентами и средства для создания рассылок между компонентами, можно избавиться от ручной проверки значений в общем состоянии, следующим образом:
![](https://habrastorage.org/webt/7w/s8/va/7ws8vae6-qqmrpm_l_9wqjbta1a.png)
Схема уведомления об изменении общего состояния
В реализации, описанной в предыдущей статье, данные изменяются в одном месте, в индексаторе компонента SharedState и поэтому контролировать их изменение очень просто
![](https://habrastorage.org/webt/uy/zv/xb/uyzvxbhx-nepvv1giwrkd7pxaeu.jpeg)
Индексатор в общем состоянии
В сеттере индексатора мы присваиваем значения состояния.
Теперь для SharedState компонента нужно добавить зависимость от SharedEvents, так как именно его и буду использовать для отправки уведомлений. Добавим атрибут для SharedState
![](https://habrastorage.org/webt/_7/l1/-n/_7l1-nuhqo6ylipqxgpsvotn8bw.jpeg)
Добавление зависимости в SharedState от SharedEvents
И создам класс, наследуемый от EventData, для отправки данных в уведомлении об изменении состояния. Он будет содержать название параметра, в состоянии и его новое значение
![](https://habrastorage.org/webt/_i/20/nz/_i20nz08kpnahewfnh3dbyxy2d4.jpeg)
Добавление класса, который содержит информацию об изменении в общем состоянии
Теперь нужно добавить ссылку на SharedEvents, получив ее из игрового объекта в компоненте SharedState
![](https://habrastorage.org/webt/r8/tq/kt/r8tqktsica48---wrqvsy_d0ho8.jpeg)
Получение SharedEvents в компоненте SharedState
Теперь изменим сеттер индексатора таким образом, чтобы при каждом изменении состояния создавалось уведомление с именем «sharedstatechanged» и передадим объект, содержащий все данные об изменении
![](https://habrastorage.org/webt/xp/dn/ck/xpdnckwptsg7xwwmpqjcmplzx9c.jpeg)
Изменение сеттера индексатора
Теперь осталось подписаться на изменения в каком либо компоненте, изменить данные в другом и проверить как это работает.
Допустим SecondComponent меняет состояние, например параметр «somedata», а компонент FirstComponent отслеживает изменение состояния, подписавшись на уведомления
В SecondComponent вызовем изменение параметра
![](https://habrastorage.org/webt/fp/uo/u3/fpuou3efwyrujfdxgia1dufdvii.jpeg)
Вызов изменения данных
И теперь в методе FirstComponent добавляем обработчик и выводим в консоль информацию об изменении общего состояния
![](https://habrastorage.org/webt/4i/js/kd/4ijskdeiwopjqe_tevz1dx7rgsg.jpeg)
Обработка события об изменении общего состояния
Теперь если запустить игру, после того как общее состояние будет изменено в SecondComponent, в компоненте FirstComponent мы получим уведомление и выведем данные в консоль
![](https://habrastorage.org/webt/sb/v9/09/sbv909u0qrag-xdvsho9xgcnfua.jpeg)
Теперь, когда это работает, можно немного отрефакторить и сделать код еще более удобным. Для этого нужно перенести подписку на уведомления об изменении общего состояния в базовый класс SharedStateComponent и создать абстрактный метод, реализовав который каждый компонент будет обрабатывать в нем изменения состояния, или нет, на усмотрение компонента.
Переносим подписку в SharedStateComponent
![](https://habrastorage.org/webt/wm/ja/v8/wmjav8ntn-fmjnlmfpzzgoy4gmm.jpeg)
Подписка на уведомления об изменении общего состояния в базовом классе
Добавляем абстрактный метод и вызываем его в обработчике события
![](https://habrastorage.org/webt/m8/_c/fd/m8_cfdykkvyyhuryvwxh7be6s8a.jpeg)
Добавление абстрактного метода, для обработки события в дочерних классах
И теперь в каждом дочернем компоненте FirstComponent и SecondComponent нужно реализовать этот метод и обработать в нем изменение общего состояния. Но мы как и прежде просто выведем это в консоль
![](https://habrastorage.org/webt/qr/ef/pl/qrefplcb2ee40ldokajn5iybrt8.jpeg)
Имплементация абстрактного метода в компонентах FirstComponent и SecondComponent
И теперь когда мы запустим игру мы увидим 2 записи в консоли, из обоих компонентов.
![](https://habrastorage.org/webt/zo/ts/_l/zots_l96h0b7kawbgjgq6pnouco.jpeg)
Важно!
В предыдущей реализации был баг в классе SharedEvents и чтобы его пофиксить нужно изменить метод Subscribe на:
![](https://habrastorage.org/webt/gc/5r/wn/gc5rwn39xjl39ui_tuag3xqr-3k.jpeg)
BertoldHolz
Не верьте в демократию;) Пишите дальше.
Если можно названия проектов или хотя бы описание проектов, в которых вы применяли данную архитектуру.
deniskozlov Автор
www.youtube.com/channel/UCHoPgKnYAwkQ9u4wtDZdeBQ/videos?sort=dd&view_as=subscriber&view=0&shelf_id=0
Тут лог разработки прототипа, где это применяется