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

1 ... 163 164 165 [ 166 ] 167 168 169 ... 196


setChangedO:

Observabl e::noti fyObservers(): alreadyOpen = true:

class Hummingbird {

void closeO { alreadyOpen = false: } } openNotifier: class CloseNotifier: friend class Flower::CloseNotifier: class CloseNotifier : public Observable {

Flower* parent:

bool alreadyClosed: public:

CloseNotifier(Flower* f) : parent(f).

alreadyClosed(false) {} void notifyObservers(Argument* arg = 0) {

if(!parent->isOpen && !alreadyClosed) { setChangedO:

Observable::notifyObserversО: alreadyClosed = true:

void openО { alreadyClosed = false: } } CloseNotifier:

class Bee { string name:

Внутренний класс для наблюдения за открытием:

class OpenObserver:

friend class Bee::OpenObserver:

class OpenObserver : public Observer {

Bee* parent: public:

OpenObserver(Bee* b) : parent(b) {} void updateCObservable*. Argument *) { cout Bee parent->name s breakfast time! endl:

} openObsrv:

Другой внутренний класс для наблюдения за закрытием:

class CloseObserver:

friend class Bee::CloseObserver:

class CloseObserver : public Observer {

Bee* parent: public:

CloseObserver(Bee* b) : parent(b) {} void update(Observable*. Argument *) { cout Bee parent->name s bed time! endl:

} closeObsrv: public: BeeCstring nm) : name(nm).

openObsrv(this), closeObsrv(this) {} Observers openObserverO { return openObsrv: } Observers CloseObserverО { return closeObsrv:}



string name: class OpenObserver:

friend class Hummingbird::OpenObserver: class OpenObserver : public Observer {

Hummingbird* parent: public:

OpenObserver(Hummingbird* h) : parent(h) {} void update(Observable*. Argument *) { cout Hummingbird parent->name s breakfast time! endl:

} openObsrv: class CloseObserver:

friend class Hummingbird::CloseObserver: class CloseObserver : public Observer {

Hummingbird* parent: public:

CloseObserver(Hummingbird* h) : parent(h) {} void update(Observable*. Argument *) { cout Hummingbird parent->name s bed time! endl:

} closeObsrv: public:

Hummingbird(string nm) : name(nm).

openObsrv(this). closeObsrv(this) {} Observers openObserverO { return openObsrv: } Observers closeObserverO { return closeObsrv:}

int mainO { Flower f:

Bee ba( A ). bb( B ): Hummingbird ha( A ). hb( B ): f.openNoti fi er.addObserver(ha.OpenObserver()): f.openNoti fi er.addObserver(hb.OpenObserver()); f.openNoti fi er.addObserver(ba.openObserver()); f.openNoti fi er.addObserver(bb.openObserver()): f.closeNoti fi er.addObserver(ha.closeObserver()); f.closeNot i fi er.addObserver(hb.closeObserver()): f.closeNoti fi er.addObserver(ba.closeObserver()): f.closeNoti fi er.addObserver(bb.closeObserver()); Объект hb перестает наблюдать за открытием: f.openNoti fi er.deleteObserver(hb.openObserver()): Происходят изменения, интересующие наблюдателей: f .openO:

f.openO: Цветок уже открыт, состояние не изменилось. Объект А перестает наблюдать за закрытием: f.closeNoti fi er.deleteObserver(

ba.closeObserverO): f.closeO:

f.closeO: Цветок уже закрыт, состояние не изменилось, f.openNoti fier.deleteObservers(): f .openO: f.closeO: } /:-

События, интересующие наблюдателей - открытие и закрытие цветка (Flower). Благодаря использованию идиомы внутреннего класса оба события наблюдаются



независимо друг от друга. Классы OpenNotifier и CloeNotifier являются производными от Observable, поэтому они обладают доступом к setChanged() и могут передаваться при любых вызовах, требующих объекта Observable. Обратите внимание: потомки Observable объявлены открытыми, что вроде бы противоречит идиоме внутреннего класса. Это объясняется тем, что некоторые из функций этих классов должны быть доступны для прикладного программиста. Нигде не сказано, что внутренний класс обязан быть закрытым; в InnerClassIdiom.cpp мы просто следуем рекомендации объявлять закрытым все, что возможно . В принципе, можно объявить классы закрытыми и предоставить опосредованный доступ к функциям через Flower, но толку от этого немного.

Идиома внутреннего класса также хорощо подходит для определения нескольких типов наблюдателей в Bee и Hummingbird, поскольку оба класса независимо наблюдают за открытием и закрытием Flower. Идиома внутреннего класса позволяет получить больщую часть достоинств наследования (в частности, возможность обращения к закрытым данным внещнего класса).

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

Если изучить предыдущий пример, вы увидите, что OpenNotifier и CloseNotifier используют базовый интерфейс Observable. А это означает, что они могли бы быть производными от соверщенно иных классов Observer; единственная связь между Observer и Flower - это интерфейс Observer.

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

Множественная диспетчеризация и паттерн Посетитель

Организация взаимодействия между несколькими типами часто является причиной хаоса в программе. Для примера возьмем систему разбора и исполнения математических выражений. Пусть нужно использовать запись вида Number + Number, Number * Number и т. д., где Number - базовый класс семейства числовых объектов. Но если в выражении а+Ь точный тип а и b неизвестен, как организовать их взаимодействие?

Нужно начать с того, о чем вы, вероятно, даже не задумывались: С++ ограничивается одинарной диспетчеризацией. Другими словами, при выполнении операции более чем с одним объектом, тип которого неизвестен, С++ позволяет задейство-



1 ... 163 164 165 [ 166 ] 167 168 169 ... 196

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