первоначально опубликовано в моем блоге по адресу первоначально опубликовано в моем блоге по адресу
Всем привет! Глава вторая в Шаблоны проектирования Head First: Руководство для мозга все о шаблоне наблюдателя. Они отмечают, насколько фундаментально и часто используется этот шаблон. А также намекнуть на идею о том, что будущие паттерны в этой книге основаны на этой и других комбинациях паттернов. Итак, давайте поговорим о шаблоне Наблюдателя.
Проблема, которую пытается решить этот шаблон, связана с коммуникацией и управлением. Простой абстрактный пример, приведенный в тексте, касается газетной издательской компании и ее подписчиков. Технически эти отношения можно классифицировать как отношения “ОДИН КО МНОГИМ”, “один издатель” и “много подписчиков”. В тексте используется термин ” Тема ” для обозначения издателя, а термин ” Наблюдатель ‘ для обозначения подписчиков.
Далее я приведу более конкретный пример. Я буду использовать пример, немного отличающийся от текста, чтобы помочь проиллюстрировать эту идею. Допустим, мы финансовый стартап, и у нас есть идея приложения для умных часов, которое может взаимодействовать со всеми вашими финансовыми учреждениями, чтобы дать вам представление о ваших финансах с высоты птичьего полета. Например, он может показать вам остатки на вашем текущем счете или цены на акции, которыми вы владеете. У нас есть доступ к классу, который может возвращать эти значения для нас, давайте назовем этот класс FinancialData . Для целей этого примера нам все равно, как он извлекает эту информацию.
Ниже приведена наивная реализация нашего приложения для смарт-часов вместе с объяснением. Конечно, все это просто псевдокод, никакого реального кода умных часов.
В этой реализации есть несколько недостатков. Во-первых, мы нарушаем принцип проектирования, изложенный в первой главе. _ Определите аспекты вашего приложения, которые различаются, и отделите их от того, что остается неизменным. _ Линии с зелеными стрелками представляют другой экран на часах, и в будущем мы, возможно, захотим добавить больше экранов. Когда это время придет, изменения в этом классе, к сожалению, неизбежны. Строки с красными стрелками извлекают финансовые данные, и хотя это тоже может измениться, это будет изменение, вызванное изменением API, а не изменением нашего кода на стороне клиента. Мы также нарушаем другой принцип проектирования: _программа для интерфейса, а не для реализации. _ Если бы только был способ, которым мы могли бы аккуратно отделить код, который меняется, от кода, который этого не делает, а также не программировать реализацию? Представляем, шаблон наблюдателя!
Шаблон наблюдателя : Определяет зависимость “один ко многим” между объектами, так что, когда один объект изменяет состояние, все его иждивенцы уведомляются и обновляются автоматически.
Мы добьемся этого и введем слабую связь с помощью интерфейсов. Давайте проиллюстрируем это определение диаграммой классов.
Теперь, используя эти диаграммы классов в качестве руководства, давайте рассмотрим реализацию нашего приложения для смарт-часов. Сначала два интерфейса приведены ниже.
public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); } public interface Observer { public void upate(Object obj); }
Далее давайте взглянем на наш новый класс финансовых данных, который реализует интерфейс Subject.
public class FinancialData implements Subject { private ArrayList observers; private float checkingBalance; private float savingsBalance; private float stockValue; private float fourOnekValue; private float weekSpending; private float monthSpending; public FinancialData(){ observers = new ArrayList(); } public void registerObserver(Observer o){ observers.add(o); } public void removeObserver(o){ int i = observers.indexOf(o); if(i > 0){ observers.remove(i); } } public void notifyObservers(){ for(int i = 0; i
Теперь давайте взглянем на одного из наших наблюдателей – экран смарт-часов Balance.
public class BalanceScreen implements Observer { private float checkingBal; private float savingsBal; private Subject financialData; public BalanceScreen(Subject financialData){ this.financialData = financialData; financialData.registerObserver(this); } public void update(Object obj){ if( obj instanceof FinancialData){ FinancialData fd = (FinancialData) obj; this.checkingBal = fd.getCheckingBalance(); this.savingsBal = fd.getSavingsBalance(); } display(); } // other BalanceScreen methods here }
Наконец, давайте взглянем на программу, чтобы склеить все это вместе.
public class SmartWatch { public static void main(String[] args){ FinancialData financialData = new FinancialData(); BalanceScreen balanceScreen = new BalanceScreen(financialData); InvestmentScreen investmentScreen = new InvestmentScreen(financialData); SpendingScreen spendingScreen = new SpendingScreen(financialData); // not using an actualy finance api, so we set values manually financialData.setNewBalanceData(348.12, 3600.87); financialData.setNewInvestmentData(899.12, 45000.65); financialData.setNewSpendingData(210.34, 677.45); // at this point we should see print statements for all 3 screens } }
Вот оно у вас! Мы внедрили интерфейсы и создали некоторый код для его тестирования. Теперь, пожалуйста, обратите внимание, что на самом деле я не запустил этот код, поэтому в этих строках может быть одна или две ошибки. Для будущего поста мне придется создать проект и разместить этот рабочий код на github. Спасибо за чтение! Ре'”рЕ½
(первоначально опубликовано в моем личном блоге: https://henricodesjava.blog )
Оригинал: “https://dev.to/henriavo/design-patterns-observer-pattern-clb”