С возвращением!🤙 Это мой второй пост из серии шаблонов проектирования. Большое спасибо O'Reilly Media за великолепную книгу. Не скупитесь и поддержите авторов и издателя: https://www.oreilly.com/library/view/head-first-design/9781492077992/
Первый пост в серии, который я рекомендую прочитать, чтобы получить общее представление о том, как все работает в серии: https://medium.com/towardsdev/strategy-pattern-for-independent-algorithms-kotlin-70ed24c7bd8b
Состав:
- вступление
- Проблема
- Принципы дизайна, которым нужно следовать
- Окончательный код решения
- Рисунок
Без лишних слов, окунемся в статью✔️
Шаблон наблюдателя
Введение
Быть инженером-программистом значит очень много. Я имею в виду, на самом деле вам нужно не просто создавать продукт, а делать это таким образом, чтобы его можно было поддерживать, изменять в будущем🔧 И я не проповедую, что паттерны — это та серебряная пуля, которая решает со всеми вашими проблемами, определенно нет🖐🏼 Я пытаюсь утверждать, что тщательно и умно спроектированная система становится намного проще в работе, а шаблоны действительно помогают в этом процессе.
Использование шаблонов упрощает и ускоряет процесс разработки. Вам не нужно болтать, просто используйте название шаблона, которое абстрагирует (о да, даже здесь🙄) скрытое значение.
Проблема
У нас есть исходный код, предоставленный нам клиентом.  Этот код, например, дает нам измерения погоды: температура☀️, давление🌬, влажность☔️
Затем эти getters запускаются основным методом measurementsChanged .  Не сосредотачивайтесь на том, как запускается этот метод, так как это пока не наше дело.
Выше была лишь короткая запись, чтобы дать вам представление.
Итак, наша задача — отправить эти данные на созданные нами дисплеи: текущие условия, статистика погоды, прогноз.
Неверная первая реализация
Вы можете придумать что-то похожее на приведенное выше:
- get...методы вернут какие-то данные (нам все равно, откуда они взяты)
- мы присоединяем эти данные к необходимым переменным, а затем обновляем наши 3 дисплея.
Что не так?🤨
- Что, если мы хотим добавить 1, 2, x количество дисплеев?  Вы будете тщательно их писать, не так ли?  =>повторяющийся код
- Если что-то является областью изменений, вам следует инкапсулировать это в отдельный класс, метод и т. д.
Встречайте шаблон Наблюдатель🥳🥳
Publisher / | \ subscriber1 subscriber2 n-1 subscriber
Издатель, известный как Subject, уведомляет подписчиковтакже называемых наблюдателями об изменениях, а в классической реализации отправляет изменения.
- Издатель реализует интерфейс издателя
- Подписчики реализовать интерфейс подписчика
Однако позже мы увидим, что есть одна лучшая модификация шаблона наблюдателя.
Суть шаблона🤌: есть один Subject, который уведомляет всех наблюдателей об изменениях. Если один из Наблюдателей решил уйти -› отправляет такое сообщение и Тема удаляет его. Наоборот, если есть объект, который хочет стать Наблюдателем -› он отправляет требуемое сообщение
Примечание: шаблон Pub-Sub похож на этот, но отличается от него.
Примечание второе: шаблон наблюдателя имеет отношение "один ко многим", где один — субъект, многие — наблюдатели.
Принципы дизайна
В этой статье у нас будет только один, но очень важный ориентир💥
- Стремитесь к слабосвязанным проектам между взаимодействующими объектами
 =› Проще говоря, ваш код не должен быть скреплен гвоздями, а должен быть гибким. Что это принесет? =› вспомнить лучшую ремонтопригодность с самого начала? Этот принцип и есть та волшебная палочка, которая помогает вам этого добиться🪄
Хорошо, а что это значит в рамках нашего паттерна?🧐
- Subject ничего не знает о наблюдателях, кроме того, что у них есть необходимый интерфейс (и наоборот). Оба могут иметь миллионы других вещей, но это не имеет значения
- Наблюдатели могут быть легко добавлены или удалены
- Subject и Observer можно использовать/модифицировать другими способами, пока они не реализуют интерфейс
Окончательный код решения
Как и прежде, не стесняйтесь смотреть на мою реализацию шаблона в Котлине.
Давайте просмотрим код и выясним, как приведенная выше схема применяется на практике.
Во-первых, я хотел бы указать, что есть 2 способа создания шаблона Observer.  В чем разница⁉️
а.  Реализация Push: Subject отправляет данные Observer через update() 
b.  Реализация Pull: Subject не принуждает данные, но наблюдатели уведомляются через update(), и в этом методе наш наблюдатель  извлекает данные через геттеры (в Java) ||  методы в Котлине
Почему Push хуже реализации Pull?
- Что, если нам нужны другие дисплеи, где не все данные из Subject нужны?
- Что, если Субъект перестанет отправлять некоторые данные или произойдут какие-то другие изменения?
В моем коде есть реализация Pull
そう、анализ кода:
- observer.ktи- subject.kt— это интерфейсы, которые определяют схему для будущих Subject и Observers.
- Субъектный интерфейс имеет 3 метода: registerObserver(),removeObserver(),notifyObservers()
- Интерфейс наблюдателя определяет один метод: update()
2. weatherData.kt — это реализация Subject.
- он содержит список observers, который сначала пуст
- у него есть такие переменные, как pressure,temperature,humidity, которые затем будут иметь некоторое содержимое
- здесь реализованы все 3 метода из интерфейса
- putNewData()— это метод, который запускается помимо данных
 — мы присоединяем эти данные к переменным, упомянутым выше
 — вызывается метод- dataChange(), который, в свою очередь, дергает- notifyObservers()(здесь этот дополнительный слой может убрать в сторону, но я решил оставить как в их Java-коде)
 - пройтись по списку наблюдателей и уведомить их через- update()
3. В firstCompanyObserver.kt находится один из дисплеев, который мы хотим построить:
- private val currWeatherData: weatherData = weatherData()определяет, какой Subject будет
- Блок initпомогает нам зарегистрировать этотobserverв упомянутом выше Subject в его списке наблюдателей.
- у нас есть переменные, которые необходимо заполнить данными.  Осторожно: может быть 2 из 3 переменных + они не abstractили что-то подобное в Subject, поэтому мы можем называть их по своему усмотрению.
- вытащить getters(на Java) || простые методы в Kotlin для заполнения их данными, когдаupdate()вызывается изnotifyObservers()вweatherData.kt
- также мы реализуем интерфейс Displayдля представления данных особым образом. Осторожно: это один из пунктов, обсуждаемых в Принципах дизайна, т. е. у нас могут быть дополнительные элементы внутри Subject или Observers.
Рисование👓

11И на рисунке у меня есть реализация Push.  WData – это наш субъект, а SObserver – наш наблюдатель.  Все вещи аналогичны описанной выше схеме.
Если вам что-то непонятно, пишите в комментариях
Кроме того, registerObserver() является примером композиции.  Как?🧐 Subject отправляет данные (при отправке) ||  уведомить (если получить) каждого наблюдателя с помощью метода update() и:
- первый не нуждается в информации о втором
- первое и второе слабо связаны друг с другом
Аутро👣
Академическое определение шаблона наблюдателя: устанавливает отношение «один ко многим» между объектами таким образом, что при изменении одного объекта все зависимые (они же наблюдатели) уведомляются и получают новые данные.
Надеюсь, вы много почерпнули из этой статьи🤩
Ты можешь меня найти:
- LinkedIn: www.linkedin.com/in/sleeplesschallenger
- GitHub: https://github.com/SleeplessChallenger
- Литкод: https://leetcode.com/SleeplessChallenger/
- Телеграмма: @SleeplessChallenger
 
                                                                     
                                                                     
                                                                    