Читаем 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.

<p>The observer example</p>

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

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

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

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

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