Меню
Главная
Авторизация/Регистрация
 
Главная arrow Информатика arrow Введение в архитектуру программного обеспечения

Паттерн Фабричный метод (Factory Method) — уровень класса

Название и классификация паттерна

Фабричный метод — паттерн, порождающий классы.

Назначение

Определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанцировать. Фабричный метод позволяет классу делегировать инстанцирование подклассам.

Известен также под именем Virtual Constructor (виртуальный конструктор).

Применимость паттерна Factory Method

В системе часто требуется создавать объекты самых разных типов. Паттерн Factory Method может быть полезным, если система должна оставаться расширяемой путем добавления объектов новых типов. Непосредственное использование выражения new является нежелательным, так как в этом случае код создания объектов с указанием конкретных типов может получиться разбросанным по всему приложению. Тогда такие операции, как добавление в систему объектов новых типов или замена объектов одного типа на другой, будут затруднительными. Паттерн Factory Method позволяет системе оставаться независимой как от самого процесса порождения объектов, так и от их типов.

  • 1. Заранее известно, когда нужно создавать объект, но неизвестен его тип.
  • 2. Класс спроектирован так, чтобы объекты, которые он создает, специфицировались подклассами.
  • 3. Класс делегирует свои обязанности одному из нескольких вспомогательных подклассов, и вы планируете локализовать знание о том, какой класс принимает эти обязанности на себя.

Описание паттерна Factory Method

Для того чтобы система оставалась независимой от различных типов объектов, паттерн Factory Method использует механизм полиморфизма — классы всех конечных типов наследуют от одного абстрактного базового класса, предназначенного для полиморфного использования. В этом базовом классе определяется единый интерфейс, через который пользователь будет оперировать объектами конечных типов.

Для обеспечения относительно простого добавления в систему новых типов паттерн Factory Method локализует создание объектов конкретных типов в специальном классе-фабрике. Методы этого класса, посредством которых создаются объекты конкретных классов, называются фабричными.

Структура

Существуют две разновидности паттерна Factory Method.

Обобщенный конструктор, когда в том же самом полиморфном базовом классе, от которого наследуют производные классы всех создаваемых в системе типов, определяется статический фабричный метод. В качестве параметра в этот метод должен передаваться идентификатор типа создаваемого объекта (рис. 32).

Классический вариант фабричного метода, когда интерфейс фабричных методов объявляется в независимом классе-фабрике, а их реализация определяется конкретными подклассами этого класса (рис. 33).

Подклассы класса Creator переопределяют абстрактную операцию Factory Method таким образом, чтобы она возвращала подходящий под-

UML-диаграмма классов паттерна Factory Method

Рис. 32. UML-диаграмма классов паттерна Factory Method.

Обобщенный конструктор

UML-диаграмма классов паттерна Factory Method

Рис. 33. UML-диаграмма классов паттерна Factory Method.

Классическая реализация

return newConcreteProduct

з

класс класса Concrete Product. Как только подкласс Creator будет инстанцирован, он может инстанцировать специфические для приложения документы, ничего не зная об их классах. Операцию Factory Method называют фабричным методом, поскольку она отвечает за «изготовление» объекта.

Участники

Product (продукт) — определяет интерфейс объектов, создаваемых фабричным методом.

ConcreteProduct (конкретный продукт) — реализует интерфейс Product.

Creator (создатель) — объявляет фабричный метод, возвращающий объект типа Product. Creator может также определять реализацию по умолчанию фабричного метода, который возвращает объект ConcreteProduct.

Может вызывать фабричный метод для создания объекта Product.

ConcreteCreator (конкретный создатель) — замещает фабричный метод, возвращающий объект ConcreteProduct.

Отношения

Создатель «полагается» на свои подклассы в определении фабричного метода, который будет возвращать экземпляр подходящего конкретного продукта.

Результаты

Фабричные методы избавляют проектировщика от необходимости встраивать в код зависящие от приложения классы. Код имеет дело только с интерфейсом класса Product, поэтому он может работать с любыми определенными пользователями классами конкретных продуктов.

Потенциальный недостаток фабричного метода состоит в том, что клиентам, возможно, придется создавать подкласс класса Creator для создания лишь одного объекта ConcreteProduct. Порождение подклассов оправданно, если клиенту так или иначе приходится создавать подклассы Creator, в противном случае клиенту придется иметь дело с дополнительным уровнем подклассов.

Пример кода

Рассмотрим оба варианта реализации паттерна Factory Method на примере процесса порождения военных персонажей для описанной ранее стратегической игры. Для упрощения демонстрационного кода будем создавать военные персонажи для некой абстрактной армии без учета особенностей воюющих сторон.

Реализация паттерна Factory Method на основе обобщенного конструктора

#include

#include

enum Warrior_ID {Infantryman_ID=0, Archer_ID, Horseman_ID };

// Иерархия классов игровых персонажей class Warrior {

public:

virtual void info() = 0; virtual ~Warrior() {}

// Параметризированный статический фабричный метод static Warrior* createWarrior( Warrior_ID id );

};

class Infantryman: public Warrior

{

public: void info() {

cout << "Infantryman" << endl;

}

};

class Archer: public Warrior

{

public: void info() {

cout << "Archer" << endl;

}

class Horseman: public Warrior

{

public: void info() {

cout << "Horseman" << endl;

}

};

// Реализация параметризированного фабричного метода Warrior* Warrior::createWarrior( Warrior_ID id )

{

Warrior * p; switch (id)

{

case Infantryman_ID: p = new Infantryman(); break;

case Archer_ID: p = new Archer(); break;

case Horseman ID: p = new Horseman(); break;

default: assert( false);

}

return p;

// Создание объектов при помощи параметризированного фабричного

метода

int main()

{

vector v;

v.push_back( Warrior: :createWarrior( Infantryman_ID));

v.push_back( Warrior::createWarrior( Archer_ID));

v.push_back( Warrior::createWarrior( Horseman_ID));

for(int i=0; iinfo();

Ц...

}

Представленный вариант паттерна Factory Method пользуется популярностью благодаря своей простоте. В нем статический фабричный метод createWarrior() определен непосредственно в полиморфном базовом классе Warrior. Этот фабричный метод является пара-метризированным, т. е. для создания объекта некоторого типа в createWarriorQ передается соответствующий идентификатор типа.

С точки зрения «чистоты» объектно-ориентированного кода у этого варианта есть следующие недостатки:

  • • так как код по созданию объектов всех возможных типов сосредоточен в статическом фабричном методе класса Warrior, то базовый класс Warrior обладает знанием обо всех производных от него классах, что является нетипичным для объектно-ориентированного подхода;
  • • подобное использование оператора switch (как в коде фабричного метода createWarrior()) в объектно-ориентированном программировании также не приветствуется.

Указанные недостатки отсутствуют в классической реализации паттерна Factory Method.

Классическая реализация паттерна Factory Method

#include

#include

// Иерархия классов игровых персонажей

class Warrior

{

public:

virtual void info() = 0; virtual ~Warrior() {}

};

class Infantryman: public Warrior

{

public: void info() {

cout << "Infantryman" << endl;

};

};

class Archer: public Warrior

{

public: void info() {

cout << "Archer" << endl;

};

class Horseman: public Warrior

{

public: void info() {

cout << "Horseman" << endl;

};

};

// Фабрики объектов class Factory

{

public:

virtual Warrior* createWarrior() = 0; virtual ~Factory() {}

};

class Infantry Factory: public Factory

{

public:

Warrior* createWarrior() { return new Infantryman;

}

};

class ArchersFactory: public Factory

{

public:

Warrior* createWarrior() { return new Archer;

}

};

class CavalryFactory: public Factory

{

public:

Warrior* createWarrior() { return new Horseman;

}

};

// Создание объектов при помощи фабрик объектов int main()

{

InfantryFactory* infantry_factory = new Infantry Factory; ArchersFactory* archers_factory = new ArchersFactory ; CavalryFactory* cavalry_factory = new CavalryFactory ;

vector v;

v.push_back( infantry_factory->createWarrior()); v.push_back( archers_factory->createWarrior()); v.push_back( cavalry_factory->createWarrior());

for(int i=0; iinfo();

Ц...

}

Классический вариант паттерна Factory Method использует идею полиморфной фабрики. Специально выделенный для создания объектов полиморфный базовый класс Factory объявляет интерфейс фабричного метода createWarrior(), а производные классы его реализуют.

Представленный вариант паттерна Factory Method является наиболее распространенным, но не единственным. Возможны следующие вариации:

  • 1) класс Factory имеет реализацию фабричного метода createWarrior() по умолчанию;
  • 2) фабричный метод createVamor() класса Factory параметризи-рован типом создаваемого объекта (как и у представленного ранее, простого варианта Factory Method) и имеет реализацию по умолчанию. В этом случае производные от Factory классы необходимы лишь для того, чтобы определить нестандартное поведение create Warrior().

Достоинства паттерна Factory Method

Создает объекты разных типов, позволяя системе оставаться независимой как от самого процесса создания, так и от типов создаваемых объектов.

Недостатки паттерна Factory Method

В случае классического варианта паттерна даже для порождения единственного объекта необходимо создавать соответствующую фабрику.

Родственные паттерны

Абстрактная фабрика часто реализуется с помощью Фабричных методов.

Паттерн Фабричный метод часто вызывается внутри Шаблонных методов.

 
Если Вы заметили ошибку в тексте выделите слово и нажмите Shift + Enter
< Пред   СОДЕРЖАНИЕ   След >
 

Популярные страницы