Планшеты

Паттерн фабричный метод c. Паттерн Factory Method (фабричный метод)

Паттерн фабричный метод c. Паттерн Factory Method (фабричный метод)

Последнее обновление: 31.10.2015

Фабричный метод (Factory Method) - это паттерн, который определяет интерфейс для создания объектов некоторого класса, но непосредственное решение о том, объект какого класса создавать происходит в подклассах. То есть паттерн предполагает, что базовый класс делегирует создание объектов классам-наследникам.

Когда надо применять паттерн

    Когда заранее неизвестно, объекты каких типов необходимо создавать

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

    Когда создание новых объектов необходимо делегировать из базового класса классам наследникам

На языке UML паттерн можно описать следующим образом:

Формальное определение паттерна на языке C# может выглядеть следующим образом:

Abstract class Product {} class ConcreteProductA: Product {} class ConcreteProductB: Product {} abstract class Creator { public abstract Product FactoryMethod(); } class ConcreteCreatorA: Creator { public override Product FactoryMethod() { return new ConcreteProductA(); } } class ConcreteCreatorB: Creator { public override Product FactoryMethod() { return new ConcreteProductB(); } }

Участники

    Абстрактный класс Product определяет интерфейс класса, объекты которого надо создавать.

    Конкретные классы ConcreteProductA и ConcreteProductB представляют реализацию класса Product. Таких классов может быть множество

    Абстрактный класс Creator определяет абстрактный фабричный метод FactoryMethod() , который возвращает объект Product.

    Конкретные классы ConcreteCreatorA и ConcreteCreatorB - наследники класса Creator, определяющие свою реализацию метода FactoryMethod() . Причем метод FactoryMethod() каждого отдельного класса-создателя возвращает определенный конкретный тип продукта. Для каждого конкретного класса продукта определяется свой конкретный класс создателя.

    Таким образом, класс Creator делегирует создание объекта Product своим наследникам. А классы ConcreteCreatorA и ConcreteCreatorB могут самостоятельно выбирать какой конкретный тип продукта им создавать.

Теперь рассмотрим на реальном примере. Допустим, мы создаем программу для сферы строительства. Возможно, вначале мы захотим построить многоэтажный панельный дом. И для этого выбирается соответствующий подрядчик, который возводит каменные дома. Затем нам захочется построить деревянный дом и для этого также надо будет выбрать нужного подрядчика:

Class Program { static void Main(string args) { Developer dev = new PanelDeveloper("ООО КирпичСтрой"); House house2 = dev.Create(); dev = new WoodDeveloper("Частный застройщик"); House house = dev.Create(); Console.ReadLine(); } } // абстрактный класс строительной компании abstract class Developer { public string Name { get; set; } public Developer (string n) { Name = n; } // фабричный метод abstract public House Create(); } // строит панельные дома class PanelDeveloper: Developer { public PanelDeveloper(string n) : base(n) { } public override House Create() { return new PanelHouse(); } } // строит деревянные дома class WoodDeveloper: Developer { public WoodDeveloper(string n) : base(n) { } public override House Create() { return new WoodHouse(); } } abstract class House { } class PanelHouse: House { public PanelHouse() { Console.WriteLine("Панельный дом построен"); } } class WoodHouse: House { public WoodHouse() { Console.WriteLine("Деревянный дом построен"); } }

В качестве абстрактного класса Product здесь выступает класс House. Его две конкретные реализации - PanelHouse и WoodHouse представляют типы домов, которые будут строить подрядчики. В качестве абстрактного класса создателя выступает Developer, определяющий абстрактный метод Create() . Этот метод реализуется в классах-наследниках WoodDeveloper и PanelDeveloper. И если в будущем нам потребуется построить дома какого-то другого типа, например, кирпичные, то мы можем с легкостью создать новый класс кирпичных домов, унаследованный от House, и определить класс соответствующего подрядчика. Таким образом, система получится легко расширяемой. Правда, недостатки паттерна тоже очевидны - для каждого нового продукта необходимо создавать свой класс создателя.

Перед прочтением ознакомьтесь с , в котором описаны принятые соглашения и понятия. Данная статья дополняется с некоторой периодичностью, так что если вы ее читали ранее, не факт что данные не изменились.

Относиться к классу порождающих паттернов. Они используются для определения и поддержания отношений между объектами. Фабричные методы избавляют проектировщика от необходимости встраивать в код зависящие от приложения классы.

Пример

Предположим мы создаем некий XML парсер, который анализирует предоставленный файл и преобразует его в DOM дерево. Каждый элемент этого дерева назовем нодой (Node). В время разбора файла, перед нами встанет задача порождения новых нод, и мы напишем там примерно такой код:

Class Xml_Node() { /*...*/ public function parse() { /*...*/ $ChildNode = new Xml_Node(); /*...*/ } /*...*/ }

Что в этом плохого? Приведу такой пример: мы захотим на основе XML файла строить структуру объектов, определенного класса, чтобы использовать ее в дальнейшем, и нам, в соответствии с принципом "до тебя уже все написано", захотелось использовать готовый класс XML_Node .

Мы делаем своего наследника XML_Node_Processor , и хотим теперь повлиять на процесс анализа файла так, чтобы при определенном теге инстанцировался определенный класс (Для тега food - My_Food , для cow - My_Big_Orange_Cow). И при реализации как приведена выше, для этого нам придется полностью перегрузить метод parse, ради того, чтобы сделать копипаст кода из родительского класса отредактировав всего одну строку кода. Согласитесь, это глупо.

Суть паттерна

Возможная реализация на PHP

Abstract class XML_Node_Abstract { abstract function createNode($tag); } class Xml_Node extends XML_Node_Abstract { /*...*/ public function createNode($tag) { return new Xml_Node(); } /*...*/ public function parse() { /*...*/ $ChildNode = $this -> createNode($Tag); /*..*/ } } class Xml_Node_Processor extends Xml_Node { public function createNode($tag) { switch($tag) { case "food": return new My_Food(); case "cow": return new My_Big_Orange_Cow(); } return parent::createNode($tag); } } class My_Food extends Xml_Node_Processor {}; class My_Big_Orange_Cow extends Xml_Node_Processor {};

В заключение

  • В реализации фабричного метода не всегда нужен абстрактный класс создателя (XML_Node_Abstract). На его месте может использоваться конкретный экземпляр. Из этого примера можно выкинуть XML_Node_Abstract и ничего не изменится
  • Результат возвращаемый фабричным методом, должен всегда соответствовать заданному интерфейсу (в нашем случае интерфейсу класса Xml_Node)
  • Фабричный метод может быть статической функцией, и использоваться для инстанации объектов подкласса
  • Фабричный метод не обязательно должен возвращать объект, он так же может возвращать класс. При этом все наследники и родители так же должны возвращать класс.

Фактически состоит из фабричных методов

Дополнено

Вопрос

Не понял. Смысл в том, чтобы в методе parse наследников создавались экземпляры именно их, а не родителя?

Почему бы вместо:

$ChildNode = new Xml_Node () ;

не сделать:

$ChildNode = new static; ?

Ответ

new static не решает проблему, решение которой возложено на фабричный метод. Его основная задача убрать зависимость из кода, зависимость от конкретного класса. Казалось бы, что плохого в этом? Ничего. Ровно до той поры, пока не потребуется расширить класс, внести некоторую логику или наладить модульное тестирование.

Вот представьте, у вас есть такой код в нескольких местах:

$node = new Xml_Node (); $title = $node->getTitle ();

Приходит к вам проект менеджер и говорит, что xml будут приходить в двух разных форматах. Подумаешь тоже:

If ($this -> isFormatOne ()) { $node = new Xml_Node (); } else { $node = new Xml_Node_Extended (); } $title = $node -> getTitle ();

Затем он приходит снова, и говорит, что форматов теперь будет 3,10,500. При такой архитектуре, придется КАЖДЫЙ раз вносить изменения во ВСЕ вхождения такого кода. Если же использовать фабричный метод, то придется изменить только его, а создания объекта будет выглядеть всегда одинково:

$node = $this -> createNode (); $title = $node -> getTitle ();

Согласен, что статья весьма сумбурная и не раскрывает всю прелесть данного паттерна, но могу вам сказать, что это один из самых простых и в тоже время полезных паттернов. Если приучить себя вместо бездумного порождения объекта делегировать эту операцию на другого, проблем станет гораздо меньше.

Описание Factory Method

Фабричный метод (англ. Factory Method также известен как Виртуальный конструктор (англ. Virtual Constructor)) - порождающий шаблон проектирования, предоставляющий подклассам интерфейс для создания экземпляров некоторого класса. В момент создания наследники могут определить, какой класс создавать. Иными словами, Фабрика делегирует создание объектов наследникам родительского класса. Это позволяет использовать в коде программы не специфические классы, а манипулировать абстрактными объектами на более высоком уровне.

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

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

Структура

  • Product - продукт
    • определяет интерфейс объектов, создаваемых абстрактным методом;
  • ConcreteProduct - конкретный продукт
    • реализует интерфейс Product ;
  • Creator - создатель
    • объявляет фабричный метод, который возвращает объект типа Product . Может также содержать реализацию этого метода «по умолчанию»;
    • может вызывать фабричный метод для создания объекта типа Product ;
  • ConcreteCreator - конкретный создатель
    • переопределяет фабричный метод таким образом, чтобы он создавал и возвращал объект класса ConcreteProduct .

Factory Method дает возможность подклассам создавать некоторые классы с помощью общего интерфейса, причем именно наследники определяют, какой родительский объект следует реализовать. То есть, нужен какой то, общий интерфейс. Этим интерфейсом в языке программирования C# может быть абстрактный класс либо интерфейс.

Представьте себе такой абстрактный класс:

Abstract class Product { public abstract decimal PurchasePrice {get; set;} public abstract decimal Price {get; set;} public abstract string Description {get; set;} }

Если мы унаследуем этот класс, то обязаны придерживаться принципа полиморфизма. То есть, переопределить все свойства этого класса, используя слово override. Давайте так и сделаем. Создаем класс, унаследованный от класса Product, который будет инкапсулировать логику конкретного продукта:

Class Computer: Product { private decimal _purchase_price; private decimal _price; private string _description; public Computer() : this(null) { } public Computer(string _description) : this(_description, 0) { } public Computer(string _description, decimal _purchase_price) : this (_description, _purchase_price, 0) { } public Computer(string _description, decimal _purchase_price, decimal _price) { this._description = _description; this._purchase_price = _purchase_price; this._price = _price; } public override string Description { get { return _description; } set { _description = value; } } public override decimal Price { get { return _price; } set { _price = value; } } public override decimal PurchasePrice { get { return _purchase_price; } set { _purchase_price = value; } } }

Класс Product - предназначен для определения интерфейса объектов, создаваемых фабричным методом. Это как бы базовая оболочка для продуктов. Продукт имеет цену и т.д. Если хотите, допишите в класс Product еще пару свойств, методов, и переопределите их в наследуемом классе. Надеюсь что пока все ясно. Прежде чем я продолжу, скажу пару слов о самом паттерне. Обычно мы используем конкретный класс и пишем вот так:

Computer computer = new Computer();

Но, данный шаблон гласит о том, что в тексте программы можно оперировать не какими-то конкретными классами, а их абстрактными представлениями. Вот наиболее популярные случаи, в которых имеет смысл применять обсуждаемый здесь шаблон:

  • класс, создающий подклассы, заранее не знает, какими они будут;
  • класс был спроектирован так, что создаваемые им объекты специфицируются подклассами;
  • класс делегирует свои обязанности одному из вспомогательных подклассов, после чего планируется локализовать знание о том, какой класс принимает эти обязанности на себя;

Вот что имеется ввиду:

На диаграмме добавилось еще два класса. Следуя шаблону, должен быть еще один абстрактный класс, в котором и будет фабричный метод. Это как бы фабрика, которая создает продукты конкретного вида. Когда определен абстрактный класс Creator с фабричным методом, мы можем создать свой унаследованный класс для конкретного продукта. Чтоб легче было понять, упростим диаграмму:

Вот и все пироги. Есть абстрактный класс продукта и создателя, в котором есть фабричный метод. Создаем класс конкретного продукта (унаследован от Product ) рас, создаем конкретный класс создатель конкретного продукта (унаследован от Creator ) два.

Вот какой вид имеет абстрактный класс Creator :

Abstract class Creator { public abstract Product FactoryMethod(); public abstract Product FactoryMethod(string _description); public abstract Product FactoryMethod(string _description, decimal _purchase_price); public abstract Product FactoryMethod(string _description, decimal _purchase_price, decimal _price); } В этом классе, я определил методы для всех видов конструкторов класса Computer. А вот создатель-класс для класса Computer: class ComputerCreator: Creator { public override Product FactoryMethod() { return new Computer(); } public override Product FactoryMethod(string _description) { return new Computer(_description); } public override Product FactoryMethod(string _description, decimal _purchase_price) { return new Computer(_description, _purchase_price); } public override Product FactoryMethod(string _description, decimal _purchase_price, decimal _price) { return new Computer(_description,_purchase_price,_price); } }

Все , теперь у нас все как на рис. 1. Видим, что фабричные методы перегружены, для того чтоб была возможность вызвать нужный конструктор класса Computer .

Создадим еще один класс CDPlayer и класс создатель для него аналогичным образом:

Класс CDPlayer :

Class CDPlayer: Product { private decimal _purchase_price; // цена закупки private decimal _price; // цена продажи // масив форматов, которые поддерживет сд плеер private string _description; public CDPlayer() : this(null) { } public CDPlayer(string _description) : this(_description, 0) { } public CDPlayer(string _description, decimal _purchase_price) : this(_description, _purchase_price, 0) { } public CDPlayer(string _description, decimal _purchase_price, decimal _price) { this._description = _description; this._purchase_price = _purchase_price; this._price = _price; } public override string Description { get { return _description; } set { _description = value; } } public override decimal Price { get { return _price; } set{ _price = value;} } public override decimal PurchasePrice { get { return _purchase_price; } set { _purchase_price = value;} } }

Создатель-класс для класса CDPlayer :

Class CDPlayerCreator: Creator { public override Product FactoryMethod() { return new CDPlayer(); } public override Product FactoryMethod(string _description) { return new CDPlayer(_description); } public override Product FactoryMethod(string _description, decimal _purchase_price) { return new CDPlayer(_description, _purchase_price); } public override Product FactoryMethod(string _description, decimal _purchase_price, decimal _price) { return new CDPlayer(_description, _purchase_price, _price); } }

Все что нам осталось, это написать клиентский код, что бы полюбоваться нашей работой.

Static void Main(string args) { ListProductList = new List(); Creator creators = new Creator; creators = new ComputerCreator(); creators = new CDPlayerCreator(); foreach (Creator cr in creators) { if (cr is ComputerCreator) productList.Add(cr.FactoryMethod("Ноут бук", 600, 800)); if (cr is CDPlayerCreator) productList.Add(cr.FactoryMethod("audio,mp3,mp4",250,360)); } foreach (Product pr in productList) { Console.WriteLine("Обьект класса {0};\n" + "Описание: {1};\n" + "Закупочная цена: {2};\n" + "Цена продажы: {3};\n", pr.GetType().Name, pr.Description, pr.PurchasePrice, pr.Price); } Console.ReadLine(); }

Вот результат программы:

Как по мне, то тут интересный факт. Экземпляр абстрактного класса создать нельзя. Но никто не говорил, что он не может служить как базовый. Если написать следующим образом, то все будет в порядке:

Product pr = new Computer();

Здесь ссылка pr (абстрактного класса) ссылается на объект класса Computer . По этой причине я спокойно могу создать специализированную коллекцию, как это и было сделано. Когда я увидел этот шаблон, я сразу заметил такие стадии разработки:

  • Абстрактный класс для объектов –> напротив класс, который его реализует для своих целей.
  • Абстрактный класс для создания объектов –> напротив класс, который его реализует для создания своих обьектов.
Иными словами:

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

ConcreteProduct (Computer, CDPlayer ) - конкретные продукты, которые участвуют в схеме, и отвечают за реализацию абстрактного класса (интерфейса) Product .

Creator - создатель, и его название говорит само за себя. Данный объект предназначен для объявления фабричного метода, возвращающего объект типа Product .

ConcreteCreator - конкретный создатель. Здесь все очевидно: конкретная реализация создателя занимается тем, что возвращает конкретный продукт. В нашем примере две конкретные реализации создателя - ComputerCreator и CDPlayerCreator .

Создатель доверяет своим подклассам реализацию подходящего онкретного продукта. В этом и заключается суть Factory Method .

Теперь отметим плюсы и минусы данного паттерна:

Самый очевидный недостаток Factory Method - необходимость создавать наследника Creator всегда, когда планируется получить новый тип продукта (т.е. новый ConcreteProduct). И этого, увы, не избежать. Но подобная проблема присутствует во многих порождающих шаблонах. К достоинствам же следует отнести возможность создавать объекты более универсально, не ориентируясь на конкретные классы и оперируя общим интерфейсом.

Паттерн Фабричный метод (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 таким образом, чтобы она возвращала подходящий под-

Рис. 32.

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

Рис. 33.

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

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 на основе обобщенного конструктора

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

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

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

public: void info() {

class Archer: public Warrior

public: void info() {

public: void info() {

// Реализация параметризированного фабричного метода 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);

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

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; i info();

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

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

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

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

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

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

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

class Infantryman: public Warrior

public: void info() {

class Archer: public Warrior

public: void info() {

class Horseman: public Warrior

public: void info() {

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

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

class Infantry Factory: public Factory

Warrior* createWarrior() { return new Infantryman;

class ArchersFactory: public Factory

Warrior* createWarrior() { return new Archer;

class CavalryFactory: public Factory

Warrior* createWarrior() { return new Horseman;

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

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

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

for(int i=0; i info();

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

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

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

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

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

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

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

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

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

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