Паттерн Наблюдатель

Паттерн Наблюдатель – поведенческий шаблон проектирования, определяет отношение «один ко многим» между субъектами таким образом, что при изменении состояния одного объекта происходит автоматическое оповещение и обновление всех зависимых компонентов.

Паттерн Наблюдатель

Реализация: совет директоров нашего автогиганта в восторге от программы, которую мы написали при рассмотрении паттерна Стратегия и в качестве награды переводят в нас отдел передовых разработок, где мы будем разрабатывать программу для приборной панели нового поколения! На приборной панели будут отображаться три показателя: скорость, обороты двигателя и давление масла. Вся информация будет браться от центрального компьютера автомобиля.

Старайтесь добиваться слабой связи между взаимодействующими объектами

Давайте применим паттерн Наблюдатель к нашей задаче. У нас есть центральный компьютер автомобиля, который хранит в себе все характеристики автомобиля и постоянно их обновляет (это будет наш объект), приборная панель выступит в качестве наблюдателя изменения нужных нам характеристик (это будет наблюдатель). Центральный компьютер будет оповещать приборную панель об изменении характеристик, в которых она заинтересована, а та в свою очередь будет отображать изменения. Пока ничего сложного, создадим класс для нашего компьютера:

Класс центрального компьютера чрезвычайно прост, в нем присутствуют один метод для моделирования изменения характеристик при движении автомобиля (changeData).

Теперь создадим интерфейс для работы с наблюдателями. В интерфейсе будет три метода: добавление наблюдателя, удаление наблюдателя и оповещение наблюдателей. И сделаем так, чтобы класс центрального компьютера его реализовывал:

И так, интерфейс Notifier содержит в себе три метода: добавление наблюдателя (addObserver), удаление наблюдателя (removeObserver) и оповещение наблюдателей (notifyObserver), первые два метода принимают в качестве параметра переменную интерфейса наблюдателя, который мы создадим позже.

Приступим к реализации интерфейса Notifier классом центрального компьютера:

Для хранения наблюдателей будем использовать переменную observers c типом List, которую инициализируем в конструкторе. Методы добавления и удаления наблюдателей очень просты, только следует отметить, что при удалении используется проверка на наличие удаляемого наблюдателя в списке. Метод notifyObserver с помощью цикла и метода update() интерфейса Observer оповещает всех слушателей об изменении данных. Вызов метода notifyObserver необходимо поместить в конце метода changeData.

Теперь приступим к работе над слушателями. В первую очередь создадим интерфейс, который будут реализовывать все слушатели:

В интерфейсе присутствует всего один метод, который необходимо реализовать для получения информации от нашего центрального компьютера (или объекта).

Далее создадим класс слушателя (приборной панели):

Переменная notifier используется для регистрации класса приборной панели в качестве слушателя, которая происходит в конструкторе. Метод update() сохраняет полученную информацию о скорости, оборотах двигателя и давлении масла от объекта (центрального процессора) и отображает ее на приборной панели по средствам метода show().

Настало время проверить в деле нашу разработку.

Результат:
Speed = 10, RPM = 2000, Oil pressure = 30
Speed = 20, RPM = 2500, Oil pressure = 40
Speed = 60, RPM = 5000, Oil pressure = 80

В качестве закрепления материала, можете попробовать расщепить класс приборной панели на составляющие — индикатор скорости, индикатор давления масла и т.д., а приборную панель сделать интерфейсом с методом отображения информации, который индикаторы будут реализовывать.

В Java присутствует встроенная реализация паттерна Наблюдатель, на мой взгляд не самая удачная, поэтому сильное внимание на нее заострять я не буду. Попробуем переписать нашу программу под реализованный в Java паттерн, для этого нам потребуется класс java.util.Observer и интерфейс java.util.Observer.

Как видите класс объекта у нас претерпел серьезные изменения, исчез конструктор с переменной для хранения слушателей, появились методы для получения скорости, оборотов и т.д.

Класс наблюдателя тоже постигли изменения, в частности конструктора и метода update().



Паттерн Наблюдатель полный код примера:

Site Footer