Читаем Thinking In C++. Volume 2: Practical Programming полностью

Notice that both inner class definitions are private, and in fact the client code doesn’t have any access to details of the implementation, since the two access functions 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 code cannot even downcast to the implementation classes, thus providing complete isolation between interface and implementation.

Just to push a point, we’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 multiply inherits 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:

//: C10:ObservedFlower.cpp

// Demonstration of "observer" pattern

#include

#include

#include

#include

#include "Observable.h"

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),

      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;}

};


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());

  // Hummingbird B decides to sleep in:

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

  // Something changes that interests observers:

  f.open();

  f.open(); // It's already open, no change.

  // Bee A doesn't want to go to bed:

  f.closeNotifier.deleteObserver(

    ba.closeObserver());

  f.close();

Перейти на страницу:

Похожие книги

3ds Max 2008
3ds Max 2008

Одни уверены, что нет лучшего способа обучения 3ds Мах, чем прочитать хорошую книгу. Другие склоняются к тому, что эффективнее учиться у преподавателя, который показывает, что и как нужно делать. Данное издание объединяет оба подхода. Его цель – сделать освоение 3ds Мах 2008 максимально быстрым и результативным. Часто после изучения книги у читателя возникают вопросы, почему не получился тот или иной пример. Видеокурс – это гарантия, что такие вопросы не возникнут: ведь автор не только рассказывает, но и показывает, как нужно работать в 3ds Мах.В отличие от большинства интерактивных курсов, где работа в 3ds Мах иллюстрируется на кубиках-шариках, данный видеокурс полностью практический. Все приемы работы с инструментами 3ds Мах 2008 показаны на конкретных примерах, благодаря чему после просмотра курса читатель сможет самостоятельно выполнять даже сложные проекты.

Владимир Антонович Верстак , Владимир Верстак

Программирование, программы, базы данных / Программное обеспечение / Книги по IT