Программирование >>  Разработка устойчивых систем 

1 ... 156 157 158 [ 159 ] 160 161 162 ... 196


содержать произвольный набор данных. При добавлении в систему нового типа Shape все изменения вносятся только в функции factory() (предполагается, что данные для инициализации объектов поступают извне; жестко закодированный массив показан только для примера).

Чтобы объекты создавались только в factory(), конструкторы конкретных подтипов Shape объявлены закрытыми, а тип Shape - дружественным (friend), чтобы функция factoryO имела доступ ко всем конструкторам (дружественной можно объявить только функцию Shape::factory(), но, похоже, объявление дружественным всего базового класса никаких проблем не создаст). У этой архитектуры есть еще одна важная особенность: базовый laiacc Shape должен располагать полной информацией обо всех производных классах, что считается нежелательным в объектно-ориентированных архитектурах. Если базовый класс приходится обновлять с включением каждого нового типа, расщирение библиотеки начинает порождать слишком много проблем. Чтобы избежать этой нежелательной циклической зависимости, следует воспользоваться полиморфными фабриками, описанными в следующем разделе.

Полиморфные фабрики

Статическая функция factory() из предыдущего примера позволяла сосредоточить все операции со.здания объектов в одном месте (единственном, в котором вносились изменения в программу). Бесспорно, это вполне разумное решение, обеспечивающее хорошую инкапсуляцию процесса создания объектов. Тем не менее, по БЧ главная цель Фабричного метода - возможность определения разных типов фабрик, производных от базовой фабрики. В сущности. Фабричный метод является особой разновидностью полиморфной фабрики. Далее приводится пример ShapeFactory2.cpp, в котором Фабричные методы размещаются в отдельном классе в виде виртуальных функции:

: C10:ShapeFactory2.cpp

Полиморфные Фабричные методы.

linclude <iostream>

linclude <map>

linclude <stnng>

linclude <vector>

linclude <stdexcept>

linclude <cstddef>

linclude ../purge.h

using namespace std:

class Shape { public:

virtual void drawO = 0:

virtual void eraseO = 0:

virtual -ShapeO {}

class ShapeFactory {

virtual Shape* createO = 0:

static map<string. ShapeFactory*> factories: public:

virtual -ShapeFactoryO {}



friend class ShapeFactorylnitializer:

class BadShapeCreation : public logic error {

public:

BadShapeCreation(string type)

: 1ogic error( Cannot create type + type) {}

static Shape*

createShape(const strings id) throw(BadShapeCreation) if(factories.find(id) != factories.endO)

return factories[id]->create(): else

throw BadShapeCreation(id):

Определение статического о&ъекта:

map<string. ShapeFactory*> ShapeFactory::factories:

class Circle : public Shape { CircleO {} Закрытый конструктор friend class ShapeFactorylnitializer: class Factory: friend class Factory: class Factory : public ShapeFactory { public:

Shape* createO { return new Circle: } friend class ShapeFactorylnitializer;

public:

void drawO { cout Circle:: draw endl: } void eraseO { cout Circle;:erase endl: } -CircleO { cout Circle: :~Circle endl; }

class Square : public Shape { SquareO {}

friend class ShapeFactorylnitializer; class Factory: friend class Factory:

class Factory : public ShapeFactory { public:

Shape* createO { return new Square; } friend class ShapeFactorylnitializer;

public:

void drawO { cout Square:: draw endl: } void eraseO { cout Square::erase endl; } -SquareO { cout Square::-Square endl; }

Синглет для инициализации ShapeFactory: class ShapeFactorylnitializer { static ShapeFactorylnitializer si; ShapeFactorylnitializerO { ShapeFactory::factories[ Circle ]= new Circle::Factory: ShapeFactory::factories[ Square ]= new Square::Factory:



-ShapeFactoryimtializerO { map<string. ShapeFactory*>::iterator it -

ShapeFactory:;factories.begin(): whileCit != ShapeFactory::factories.endO)

delete it++->second:

Определение статического объекта: ShapeFactorylnitializer ShapeFactorylnitializer::si:

char* sl[] = { Circle . Square . Square . Circle . Circle . Circle . Square }:

int mainO { vector<Shape*> shapes: try {

for(size t i = 0: i < sizeof si / sizeof sl[0]; i++) shapes.push back(ShapeFactory::createShapeC si [i])): } catch(ShapeFactory::BadShapeCreation e) { cout e.what О endl: return EXITJAILURE:

for(size t i = 0: i < shapes.sizeO: i++) { shapes[i]->draw(): shapes[i]->erase():

purge(shapes): } III:-

В новой версии Фабричный метод находится в отдельном классе ShapeFactory в виде виртуальной функции create(). Функция объявлена закрытой, то есть она не может вызываться напрямую, но может переопределяться. Подклассы Shape должны создать собственные подклассы ShapeFactory и переопределить функцию create() для создания объекта своего типа. Вследствие своей закрытости фабрики доступны только из главного Фабричного метода. Следовательно, чтобы создать объект, весь клиентский код должен действовать через Фабричный метод.

Непосредственное создание объектов осуществляется вызовом ShapeFacto-ry::createShape() - статической функции, которая путем отображения в ShapeFactory находит соответствующий объект фабрики по переданному идентификатору. Фабрика непосредственно создает объект, хотя при желании можно представить более сложную ситуацию, в которой объект-фабрика возвращается и используется вызывающей стороной для создания объекта более изощренным способом. Впрочем, чаще сложности полиморфного Фабричного метода отказываются излишними, и решение со статической функцией в базовом классе (см. программу ShapeFactoryl.cpp) работает нормально.

Обратите внимание: объект ShapeFactory необходимо инициализировать и заполнить отображение объектами фабрик; это происходит в Синглете ShapeFactorylmtiahzer. Итак, чтобы добавить новый тип в эту архитектуру, вы должны определить тип, создать фабрику и модифицировать Синглет ShapeFactorylnitializer, чтобы экземпляр фабрики сохранялся в отображении. Все эти сложности снова наводят на мысль, что если вам не требуется создавать самостоятельные объекты фабрик, лучше воспользоваться статическим Фабричным методом.



1 ... 156 157 158 [ 159 ] 160 161 162 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика