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

    return os << "Paper   ";

  }

};

class Scissors : public Item {

public:

  Outcome compete(const Item* it) {

    return it->eval(this);

  }

  Outcome eval(const Paper*) const {

    return lose;

  }

  Outcome eval(const Scissors*) const {

    return draw;

  }

  Outcome eval(const Rock*) const {

    return win;

  }

  ostream& print(ostream& os) const {

    return os << "Scissors";

  }

};

class Rock : public Item {

public:

  Outcome compete(const Item* it) {

    return it->eval(this);

  }

  Outcome eval(const Paper*) const {

    return win;

  }

  Outcome eval(const Scissors*) const {

    return lose;

  }

  Outcome eval(const Rock*) const {

    return draw;

  }

  ostream& print(ostream& os) const {

    return os << "Rock    ";

  }

};

struct ItemGen {

  ItemGen() { srand(time(0)); }

  Item* operator()() {

    switch(rand() % 3) {

      default:

      case 0:

        return new Scissors;

      case 1:

        return new Paper;

      case 2:

        return new Rock;

    }

  }

};

struct Compete {

  Outcome operator()(Item* a, Item* b) {

    cout << a << "\t" << b << "\t";

    return a->compete(b);

  }

};

int main() {

  const int sz = 20;

  vector v(sz*2);

  generate(v.begin(), v.end(), ItemGen());

  transform(v.begin(), v.begin() + sz,

    v.begin() + sz,

    ostream_iterator(cout, "\n"),

    Compete());

  purge(v);

} ///:~

<p>Multiple dispatching with Visitor</p>

The assumption is that you have a primary class hierarchy that is fixed; perhaps it’s from another vendor and you can’t make changes to that hierarchy. However, you’d like to add new polymorphic member functions to that hierarchy, which means that normally you’d have to add something to the base class interface. So the dilemma is that you need to add member functions to the base class, but you can’t touch the base class. How do you get around this?

The design pattern that solves this kind of problem is called a "visitor" (the final one in Design Patterns), and it builds on the double-dispatching scheme shown in the previous section.

The Visitor pattern allows you to extend the interface of the primary type by creating a separate class hierarchy of type Visitor to "virtualize" the operations performed on the primary type. The objects of the primary type simply "accept" the visitor and then call the visitor’s dynamically-bound member function.

//: C10:BeeAndFlowers.cpp

// Demonstration of "visitor" pattern

#include

#include

#include

#include

#include

#include

#include "../purge.h"

using namespace std;

class Gladiolus;

class Renuculus;

class Chrysanthemum;

class Visitor {

public:

  virtual void visit(Gladiolus* f) = 0;

  virtual void visit(Renuculus* f) = 0;

  virtual void visit(Chrysanthemum* f) = 0;

  virtual ~Visitor() {}

};

class Flower {

public:

  virtual void accept(Visitor&) = 0;

  virtual ~Flower() {}

};

class Gladiolus : public Flower {

public:

  virtual void accept(Visitor& v) {

    v.visit(this);

  }

};

class Renuculus : public Flower {

public:

  virtual void accept(Visitor& v) {

    v.visit(this);

  }

};

class Chrysanthemum : public Flower {

public:

  virtual void accept(Visitor& v) {

    v.visit(this);

  }

};

// Add the ability to produce a string:

class StringVal : public Visitor {

  string s;

public:

  operator const string&() { return s; }

  virtual void visit(Gladiolus*) {

    s = "Gladiolus";

  }

  virtual void visit(Renuculus*) {

    s = "Renuculus";

  }

  virtual void visit(Chrysanthemum*) {

    s = "Chrysanthemum";

  }

};

// Add the ability to do "Bee" activities:

class Bee : public Visitor {

public:

  virtual void visit(Gladiolus*) {

    cout << "Bee and Gladiolus\n";

  }

  virtual void visit(Renuculus*) {

    cout << "Bee and Renuculus\n";

  }

  virtual void visit(Chrysanthemum*) {

    cout << "Bee and Chrysanthemum\n";

  }

};

struct FlowerGen {

  FlowerGen() { srand(time(0)); }

  Flower* operator()() {

    switch(rand() % 3) {

      default:

      case 0: return new Gladiolus;

      case 1: return new Renuculus;

      case 2: return new Chrysanthemum;

    }

  }

};

int main() {

  vector v(10);

  generate(v.begin(), v.end(), FlowerGen());

  vector::iterator it;

  // It's almost as if I added a virtual function

  // to produce a Flower string representation:

  StringVal sval;

  for(it = v.begin(); it != v.end(); it++) {

    (*it)->accept(sval);

    cout << string(sval) << endl;

  }

  // Perform "Bee" operation on all Flowers:

  Bee bee;

  for(it = v.begin(); it != v.end(); it++)

    (*it)->accept(bee);

  purge(v);

} ///:~

<p>Exercises</p>

1.Starting with SingletonPattern.cpp, create a class that provides a connection to a service that stores and retrieves data from a configuration file.

2.Using SingletonPattern.cpp as a starting point, create a class that manages a fixed number of its own objects. Assume the objects are database connections and you only have a license to use a fixed quantity of these at any one time.

3.Create a minimal Observer-Observable design in two classes, without base classes and without the extra arguments in Observer.h and the member functions in Observable.h. Just create the bare minimum in the two classes, and then demonstrate your design by creating one Observable and many Observers and cause the Observable to update the Observers.

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

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

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

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

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

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

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

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

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