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

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

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

3ds Max 2008
3ds Max 2008

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

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

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