Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
B.Eckel - Thinking in C++, Vol.2, 2nd edition.pdf
Скачиваний:
50
Добавлен:
08.05.2013
Размер:
2.09 Mб
Скачать

} ///:~

The example begins with the Poingable and Bingable interfaces, each of which contain a single member function. The services provided by callPoing( ) and callBing( ) require that the object they receive implement the Poingable and Bingable interfaces, respectively, but they put no other requirements on that object so as to maximize the flexibility of using callPoing( ) and callBing( ). Note the lack of virtual destructors in either interface – the intent is that you never perform object destruction via the interface.

Outer contains some private data (name) and it wishes to provide both a Poingable interface and a Bingable interface so it can be used with callPoing( ) and callBing( ). Of course, in this situation we could simply use multiple inheritance. This example is just intended to show the simplest syntax for the idiom; we’ll see a real use shortly. To provide a Poingable object without inheriting Outer from Poingable, the inner class idiom is used. First, the declaration class Inner says that, somewhere, there is a nested class of this name. This allows the friend declaration for the class, which follows. Finally, now that the nested class has been granted access to all the private elements of Outer, the class can be defined. Notice that it keeps a pointer to the Outer which created it, and this pointer must be initialized in the constructor. Finally, the poing( ) function from Poingable is implemented. The same process occurs for the second inner class which implements Bingable. Each inner class has a single private instance created, which is initialized in the Outer constructor. By creating the member objects and returning references to them, issues of object lifetime are eliminated.

Notice that both inner class definitions are private, and in fact the client programmer doesn’t have any access to details of the implementation, since the two access methods operator Poingable&( ) and operator Bingable&( ) only return a reference to the upcast interface, not to the object that implements it. In fact, since the two inner classes are private, the client programmer cannot even downcast to the implementation classes, thus providing complete isolation between interface and implementation.

Just to push a point, I’ve taken the extra liberty here of defining the automatic type conversion operators operator Poingable&( ) and operator Bingable&( ). In main( ), you can see that these actually allow a syntax that looks like Outer is multiply inherited from Poingable and Bingable. The difference is that the casts in this case are one way. You can get the effect of an upcast to Poingable or Bingable, but you cannot downcast back to an Outer. In the following example of observer, you’ll see the more typical approach: you provide access to the inner class objects using ordinary member functions, not automatic type conversion operations.

The observer example

Armed with the Observer and Observable header files and the inner class idiom, we can look at an example of the observer pattern:

//: C09:ObservedFlower.cpp

// Demonstration of "observer" pattern #include "Observable.h"

#include <iostream> #include <vector>

Chapter 16: Design Patterns

455

#include <algorithm> #include <string> using namespace std;

class Flower { bool isOpen;

public:

Flower() : isOpen(false), openNotifier(this), closeNotifier(this) {}

void open() { // Opens its petals isOpen = true; openNotifier.notifyObservers(); closeNotifier.open();

}

void close() { // Closes its petals isOpen = false; closeNotifier.notifyObservers(); openNotifier.close();

}

// Using the "inner class" idiom: class OpenNotifier;

friend class Flower::OpenNotifier;

class OpenNotifier : public Observable { Flower* parent;

bool alreadyOpen; public:

OpenNotifier(Flower* f) : parent(f), alreadyOpen(false) {}

void notifyObservers(Argument* arg=0) { if(parent->isOpen && !alreadyOpen) {

setChanged();

Observable::notifyObservers(); alreadyOpen = true;

}

}

void close() { alreadyOpen = false; } } openNotifier;

class CloseNotifier;

friend class Flower::CloseNotifier;

class CloseNotifier : public Observable { Flower* parent;

bool alreadyClosed; public:

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

Chapter 16: Design Patterns

456

alreadyClosed(false) {}

void notifyObservers(Argument* arg=0) { if(!parent->isOpen && !alreadyClosed) {

setChanged();

Observable::notifyObservers(); alreadyClosed = true;

}

}

void open() { alreadyClosed = false; } } closeNotifier;

};

class Bee { string name;

// An "inner class" for observing openings: class OpenObserver;

friend class Bee::OpenObserver;

class OpenObserver : public Observer { Bee* parent;

public:

OpenObserver(Bee* b) : parent(b) {} void update(Observable*, Argument *) {

cout << "Bee " << parent->name << "'s breakfast time!\n";

}

} openObsrv;

// Another "inner class" for closings: 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!\n";

}

} closeObsrv; public:

Bee(string nm) : name(nm), openObsrv(this), closeObsrv(this) {}

Observer& openObserver() { return openObsrv; } Observer& closeObserver() { return closeObsrv;}

};

Chapter 16: Design Patterns

457

class Hummingbird { 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!\n";

}

} 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!\n";

}

} closeObsrv; public:

Hummingbird(string nm) : name(nm), openObsrv(this), closeObsrv(this) {}

Observer& openObserver() { return openObsrv; } Observer& closeObserver() { return closeObsrv;}

};

int main() { Flower f;

Bee ba("A"), bb("B"); Hummingbird ha("A"), hb("B");

f.openNotifier.addObserver(ha.openObserver());

f.openNotifier.addObserver(hb.openObserver());

f.openNotifier.addObserver(ba.openObserver());

f.openNotifier.addObserver(bb.openObserver());

f.closeNotifier.addObserver(ha.closeObserver());

f.closeNotifier.addObserver(hb.closeObserver());

f.closeNotifier.addObserver(ba.closeObserver());

f.closeNotifier.addObserver(bb.closeObserver());

Chapter 16: Design Patterns

458

Соседние файлы в предмете Численные методы
  • #
    08.05.20133.99 Mб22A.Menezes, P.van Oorschot,S.Vanstone - HANDBOOK OF APPLIED CRYPTOGRAPHY.djvu
  • #
  • #
    08.05.20135.91 Mб24B.Eckel - Thinking in Java, 3rd edition (beta).pdf
  • #
  • #
    08.05.20136.09 Mб17D.MacKay - Information Theory, Inference, and Learning Algorithms.djvu
  • #
    08.05.20133.85 Mб15DIGITAL Visual Fortran ver.5.0 - Programmers Guide to Fortran.djvu
  • #
    08.05.20131.84 Mб12E.A.Lee, P.Varaiya - Structure and Interpretation of Signals and Systems.djvu