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

  class BadShapeCreation : public logic_error {

  public:

    BadShapeCreation(string type)

      : logic_error("Cannot create type " + type)

    {}

  };

  static Shape* factory(const string& type)

    throw(BadShapeCreation);

};

class Circle : public Shape {

  Circle() {} // Private constructor

  friend class Shape;

public:

  void draw() { cout << "Circle::draw\n"; }

  void erase() { cout << "Circle::erase\n"; }

  ~Circle() { cout << "Circle::~Circle\n"; }

};

class Square : public Shape {

  Square() {}

  friend class Shape;

public:

  void draw() { cout << "Square::draw\n"; }

  void erase() { cout << "Square::erase\n"; }

  ~Square() { cout << "Square::~Square\n"; }

};

Shape* Shape::factory(const string& type)

  throw(Shape::BadShapeCreation) {

  if(type == "Circle") return new Circle;

  if(type == "Square") return new Square;

  throw BadShapeCreation(type);

}

char* shlist[] = { "Circle", "Square", "Square",

  "Circle", "Circle", "Circle", "Square", "" };

int main() {

  vector shapes;

  try {

    for(char** cp = shlist; **cp; cp++)

      shapes.push_back(Shape::factory(*cp));

  } catch(Shape::BadShapeCreation e) {

    cout << e.what() << endl;

    purge(shapes);

    return 1;

  }

  for(size_t i = 0; i < shapes.size(); i++) {

    shapes[i]->draw();

    shapes[i]->erase();

  }

  purge(shapes);

} ///:~

The factory( ) function takes an argument that allows it to determine what type of Shape to create; it happens to be a string in this case, but it could be any set of data. The factory( ) is now the only other code in the system that needs to be changed when a new type of Shape is added. (The initialization data for the objects will presumably come from somewhere outside the system and will not be a hard-coded array as in the previous example.)

To ensure that the creation can only happen in the factory( ), the constructors for the specific types of Shape are made private, and Shape is declared a friend so that factory( ) has access to the constructors. (You could also declare only Shape::factory( ) to be a friend, but it seems reasonably harmless to declare the entire base class as a friend.)

<p>Polymorphic factories</p>

The static factory( ) member function in the previous example forces all the creation operations to be focused in one spot, so that’s the only place you need to change the code. This is certainly a reasonable solution, as it nicely encapsulates the process of creating objects. However, Design Patterns emphasizes that the reason for the Factory Method pattern is so that different types of factories can be derived from the basic factory. Factory Method is in fact a special type of polymorphic factory. However, Design Patterns does not provide an example, but instead just repeats the example used for the Abstract Factory. Here is ShapeFactory1.cpp modified so the Factory Methods are in a separate class as virtual functions:

//: C10:ShapeFactory2.cpp

// Polymorphic Factory Methods

#include

#include

#include

#include

#include

#include "../purge.h"

using namespace std;

class Shape {

public:

  virtual void draw() = 0;

  virtual void erase() = 0;

  virtual ~Shape() {}

};

class ShapeFactory {

  virtual Shape* create() = 0;

  static map factories;

public:

  virtual ~ShapeFactory() {}

  friend class ShapeFactoryInitializer;

  class BadShapeCreation : public logic_error {

  public:

    BadShapeCreation(string type)

      : logic_error("Cannot create type " + type)

    {}

  };

  static Shape*

  createShape(const string& id) throw(BadShapeCreation){

    if(factories.find(id) != factories.end())

      return factories[id]->create();

    else

      throw BadShapeCreation(id);

  }

};

// Define the static object:

map

  ShapeFactory::factories;

class Circle : public Shape {

  Circle() {} // Private constructor

public:

  void draw() { cout << "Circle::draw\n"; }

  void erase() { cout << "Circle::erase\n"; }

  ~Circle() { cout << "Circle::~Circle\n"; }

private:

  friend class ShapeFactoryInitializer;

  class Factory;

  friend class Factory;

  class Factory : public ShapeFactory {

  public:

    Shape* create() { return new Circle; }

    friend class ShapeFactoryInitializer;

  };

};

class Square : public Shape {

  Square() {}

public:

  void draw() { cout << "Square::draw\n"; }

  void erase() { cout << "Square::erase\n"; }

  ~Square() { cout << "Square::~Square\n"; }

private:

  friend class ShapeFactoryInitializer;

  class Factory;

  friend class Factory;

  class Factory : public ShapeFactory {

  public:

    Shape* create() { return new Square; }

    friend class ShapeFactoryInitializer;

  };

};

// Singleton to initialize the ShapeFactory:

class ShapeFactoryInitializer {

  static ShapeFactoryInitializer si;

  ShapeFactoryInitializer() {

    ShapeFactory::factories["Circle"] =

      new Circle::Factory;

    ShapeFactory::factories["Square"] =

      new Square::Factory;

  }

  ~ShapeFactoryInitializer() {

    delete ShapeFactory::factories["Circle"];

    delete ShapeFactory::factories["Square"];

  }

};

// Static member definition:

ShapeFactoryInitializer

  ShapeFactoryInitializer::si;

char* shlist[] = { "Circle", "Square", "Square",

  "Circle", "Circle", "Circle", "Square", "" };

int main() {

  vector shapes;

  try {

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

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

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

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

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

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

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

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

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