1.2 Применения шаблона
Использовать данный паттерн рационально в следующих ситуациях:
1) существует, как минимум, один объект, рассылающий сообщения;
2) имеется не менее одного получателя сообщений, причём их количество и состав могут изменяться во время работы приложения;
3) нет надобности очень сильно связывать взаимодействующие объекты, что полезно для повторного использования.
Данный шаблон часто применяют в ситуациях, в которых отправителя сообщений не интересует, что делают получатели с предоставленной им информацией.
2 СТРУКТУРА ШАБЛОНА
Структура паттерна продемонстрирована ниже на рисунке 2.
Рисунок 2 – Структура шаблона
Subject – объект, который имеет нужною информацию про наблюдателей, число следящих наблюдателей может быть любым. Его реализация это интерфейс, который имеет методы управления наблюдателями. Он может быть добавлен метод Attach(O) или отдален Detach(O). Метод Notify() используется для возобновления работы потока.
ConcreteSubject – конкретный субъект, сохраняет свое состояние, предоставляя интерес для конкретного наблюдателя. Отправляет информацию наблюдателям когда происходит изменение, имеет методы GetState() и также метод SetState(). Поле subjectState, хранит в себе информацию про состояние субъекта. С помощью первого метода мы получаем информацию, с помощью второго мы устанавливаем информацию.
Observer – объект, наблюдатель. Класс, который реализует интерфейс для обновления всех объектов, которые будут проинформированы после изменения субъекта. Имеет метод Update().
ConcreteObserver – объект, конкретный наблюдатель. Этот класс хранит ссылку на объект класса ConcreteSubject. Сохраняет данные, которые должны быть согласованными с данными субъекта. Реализует интерфейс обновления, который определен в классе Observer, чтобы поддерживать отношения согласованности с субъектом. Имеет метод Update() который необходим ему для обновления информации и поле observerState – которое хранит информацию о состояние наблюдателя.
При изменении наблюдаемого объекта, оповещения наблюдателей может быть реализовано по следующим сценариями:
Наблюдаемый объект отправляет, каждому из зарегистрированных наблюдателей, все потенциально релевантных информацию (принудительное распространение).
Наблюдаемый объект отправляет, каждому из зарегистрированных наблюдателей, лишь СООБЩЕНИЕ о тех, что информация была изменена, а КАЖДЫЙ С наблюдателей, при необходимости, самостоятельно осуществляет запрос необходимой информации в наблюдаемого объекта (распространение по запросу).
3 РЕАЛИЗАЦИЯ
Для демонстрации шаблона наблюдатель, будем реализовывать космический корабль. Космический корабль может передвигаться, ускоряться, сбрасывать скорость, активировать\деактивировать щит. Для этого нам понадобиться реализовать все эти методы, но нам же надо как то получать данные про наш корабль, например текущею скорость или координаты местонахождения в пространстве. Для этого мы создадим монитор, то есть экран на котором нам будет изображаться текущая скорость, статус защитного щита и координаты. Это и будет наш наблюдатель.
В таком случае субъектом будет космический корабль, объектом наблюдателем будет монитор статус. Корабль может также иметь и другие датчики, дисплеи, но мы рассмотрим именно монитор, который отобразит нам текущую ситуацию.
Создадим интерфейсы Observer, Subject и определим в них методы указанные в структуре. Создадим два класса, которые будут реализовывать эти интерфейсы SpaceShip и SpaceShipMonitor.
В SpaceShip определим следующие поля:
Monitors – список мониторов.
Coordinates – будет означать текущие местоположение нашего космического корабля в пространстве.
ShieldStatus – показывает нам активирован ли на данные момент щит. Цифра 1 – да, 0 – нет.
CurrentVelocity – показывает нам текущую скорость корабля.
В SpaceShip определим следующие методы:
Speed() – добавляет или сбавляет скорость.
Move() – двигает корабль из одной точки в другую.
Shield() – активирует и деактивирует щит.
И переопределяем методы интерфейса Subject.
В классе SpaceShipMonitor определим следующие поля:
Subject – объект нашего корабля.
Status – переменная которая хранит в себе статус корабля.
В классе SpaceShipMonitor определим следующие методы:
MonitorOff() – удалить этот монитор с корабля, а также реализуем методы интерфейса Observer.
В классе SpaceShipMonitor определим следующие конструкторы:
Конструктор добавления монитора на корабль, конструктор инициализации.
В итоге получаем такую панель управления:
Рисунок 3 – GUI нашей программы
Рисунок 4 – GUI нашей программы, после изменения
