Программирование >>  Разработка устойчивых систем 

1 ... 161 162 163 [ 164 ] 165 166 167 ... 196


Built а MountainBike Built a RacingBike Built a RacingBike Built a RacingBike Built a TouringBike Bicycle: {

Frame Wheel Seat Derailleur Handlebar Sprocket Shock } Bicycle: {

Frame Wheel Seat Derailleur Handlebar Sprocket Shock } Bicycle: { Frame Wheel Seat Handlebar Sprocket } Bicycle: { Frame Wheel Seat Handlebar Sprocket } Bicycle: { Frame Wheel Seat Handlebar Sprocket } Bicycle: {

Frame Wheel Seat Derailleur Handlebar Sprocket Rack } */ III:-

Главным достоинством этого паттерна является то, что он отделяет алгоритм сборки окончательного продукта от частей и позволяет использовать разные алгоритмы для разных продуктов за счет выбора разных реализаций общего интерфейса.

Наблюдатель

Паттерн Наблюдатель (Observer) рещает довольно распространенную задачу: что, если изменение состояния одного объекта должно приводить к автоматическому обновлению нескольких других объектов? В частности, эта задача встречается в паре модель-представление архитектуры Smalltalk модель-представление-контроллер (Model-View-Controller, MVC) и почти эквивалентной архитектуре документ-представление. Допустим, имеются некоторые данные ( документ ) и два представления: графическое и текстовое. Изменение данных должно привести к обновлению представлений; это и делает Наблюдатель.

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

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

Паттерн Наблюдатель можно реализовать разными способами. Код, приведенный далее, задает общую структуру, на базе которой вы можете построить собственное рещение. Для начала объект-наблюдатель описывается следующим интерфейсом:

: СЮ:Observer.h Интерфейс Observer. #ifndef OBSERVERS #define OBSERVERJ

class Observable: class Argument {}:

class Observer { public:



Вызывается наблюдаемым объектом при каждом его изменении: virtual void update(Observable* о. Argument* arg) = 0: virtual -ObserverO {}

#endif OBSERVER H 111 -

Так как Observer в этом решении взаимодействует с Observable, начинать нужно с объявления Observable. Пустой класс Argument действует только как базовый класс для любого типа аргумента, передаваемого при обновлении. При желании дополнительный аргумент можно передавать просто в виде void*. В обоих случаях вам придется выполнить понижающее преобразование.

Тип Observer представляет интерфейсный класс, содержащий единственную функцию update(). Эта функция вызывается наблюдаемым объектом, когда он решает, что пришло время обновить все наблюдающие объекты. Наличие аргументов не обязательно; вызов функции update() без аргументов все равно соответствует паттерну. Тем не менее, форма с аргументом более универсальна - вместе с оповещением можно передать объект, ставший причиной обновления (поскольку Observer может регистрироваться с несколькими наблюдаемыми объектами), и любую полезную дополнительную информацию. Без аргумента объекту Observer приходится самому выяснять, какой объект инициировал обновление, и собирать всю необходимую информацию.

Наблюдаемый объект относится к типу Observable:

: C10:0bservable.h Класс Observable. #ifndef OBSERVABLEJ #define OBSERVABLE H #include <set> #include Observer.h

class Observable { bool changed:

std::set<Observer*> observers: protected:

virtual void setChangedO { changed = true: } virtual void clearChanged() { changed = false: } public:

virtual void addObserver(Observer& o) { observers.insert(&o):

virtual void deleteObserver(Observer& o) { observers.erase(&o):

virtual void deleteObserversC) { observers.clearO:

virtual int countObservers() { return observers.SizeO:

virtual bool hasChangedO { return changed: }

Если объект изменился, оповестить всех наблюдателей:

virtual void notifyObservers(Argument* arg = 0) {

if(lhasChangedO) return:

clearChangedO: Снять признак измененности

std::set<Observer*>::iterator it:

for(it = observers.beginO:it != observers.end(): it++)



Отличие состоит в том, что java.util.Observable.notifyOvservers() не вызывает функцию clearChanged() после оповещения наблюдателей.

virtual -ObservableO {}

#endif OBSERVABLEJ /:-

И снова архитектура получается более сложной, чем необходимо. Если Observable может регистрировать объекты Observer и обновлять их, конкретный набор функций значения не имеет. Тем не менее, эта архитектура ориентирована на многократное использование (за образец была взята архитектура стандартной библиотеки Java).

Объект Observable содержит флаг, указывающий, что объект был изменен. В более простой архитектуре такой флаг отсутствует; если с объектом что-нибудь происходит, об этом оповещаются все наблюдатели. Но стоит заметить, что функции, управляющие состоянием флага, объявлены защищенными, поэтому рещить, что именно следует считать изменением, может только производный класс, но не конечный пользователь производного класса Observer.

Коллекция объектов Observer хранится в множестве set<Observer*> для предотвращения возможных дубликатов. Класс предоставляет стандартные операции множеств insert(), erase(), clear() и size() для произвольного добавления и удаления наблюдателей; тем самым обеспечивается необходимая гибкость на стадии выполнения.

Большая часть работы происходит в вызове notifyObservers(). Если флаг changed() не был установлен, вызов не делает ничего. В противном случае он сначала сбрасывает флаг changed, чтобы предотвратить напрасную трату времени при повторных вызовах notifyObservers(). Это делается перед оповещением наблюдателей на тот случай, если вызовы update() приведут к изменениям в объекте Observable. Затем функция перебирает элементы множества и вызывает функцию update() каждого объекта Observer.

На первый взгляд может показаться, что для управления обновлениями можно воспользоваться обычным объектом Observable. Но такое решение работать не будет; чтобы добиться какого-нибудь эффекта, вы должны создать класс, производный от Observable, и где-то в коде производного класса вызвать функцию setChanged(). Эта функция устанавливает признак изменения, чтобы вызов notifyObservers() действительно приводил к оповещению наблюдателей. А когда именно вызывать setChanged(), зависит от логики программы.

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

Проблема в том, что в подобных ситуациях обычно хочется воспользоваться множественным наследованием: Сначала унаследуем от Observable, чтобы обработать щелчки, потом... унаследуем от Observable, чтобы обработать перемещение указателя и, наконец,... хм, ничего не выйдет .

(*it)->update(th1s. arg):



1 ... 161 162 163 [ 164 ] 165 166 167 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика