- Фабричный метод (шаблон проектирования)
-
Шаблон проектирования Фабричный метод Factory Method Тип: порождающий
Описан в Design Patterns Да
Фабричный метод (англ. Factory Method) — порождающий шаблон проектирования, предоставляющий подклассам интерфейс для создания экземпляров некоторого класса. В момент создания наследники могут определить, какой класс создавать. Иными словами, Фабрика делегирует создание объектов наследникам родительского класса. Это позволяет использовать в коде программы не специфические классы, а манипулировать абстрактными объектами на более высоком уровне. Также известен под названием виртуальный конструктор (англ. Virtual Constructor).
Содержание
Цель
Определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанциировать. Фабричный метод позволяет классу делегировать создание подклассов. Используется, когда:
- классу заранее неизвестно, объекты каких подклассов ему нужно создавать.
- класс спроектирован так, чтобы объекты, которые он создаёт, специфицировались подклассами.
- класс делегирует свои обязанности одному из нескольких вспомогательных подклассов, и планируется локализовать знание о том, какой класс принимает эти обязанности на себя.
Структура
- Product — продукт
- определяет интерфейс объектов, создаваемых абстрактным методом;
- ConcreteProduct — конкретный продукт
- реализует интерфейс Product;
- Creator — создатель
- объявляет фабричный метод, который возвращает объект типа Product. Может также содержать реализацию этого метода «по умолчанию»;
- может вызывать фабричный метод для создания объекта типа Product;
- ConcreteCreator — конкретный создатель
- переопределяет фабричный метод таким образом, чтобы он создавал и возвращал объект класса ConcreteProduct.
Плюсы
- позволяет сделать код создания объектов более универсальным, не привязываясь к конкретным классам (ConcreteProduct), а оперируя лишь общим интерфейсом (Product);
- позволяет установить связь между параллельными иерархиями классов.
Минусы
- необходимость создавать наследника Creator для каждого нового типа продукта (ConcreteProduct).
Примеры
Python
Исходный текст на языке Python#coding: utf-8 """ Типы строя """ class Culture: """ Культура """ def __repr__(self): return self.__str__() class Democracy(Culture): def __str__(self): return 'Democracy' class Dictatorship(Culture): def __str__(self): return 'Dictatorship' """ Само правительство """ class Government: culture = '' def __str__(self): return self.culture.__str__() def __repr__(self): return self.culture.__repr__() def set_culture(self): """ Задать строй правительству : это и есть наш Фабричный Метод """ raise AttributeError('Not Implemented Culture') """ Правительство 1 """ class GovernmentA(Government): def set_culture(self): self.culture = Democracy() """ Правительство 2 """ class GovernmentB(Government): def set_culture(self): self.culture = Dictatorship() g1 = GovernmentA() g1.set_culture() print (str(g1)) g2 = GovernmentB() g2.set_culture() print (str(g2))
Ruby
Исходный текст на языке Rubyclass One; end class Two; end class Factory def self.build str_class class_eval "#{str_class}.new" end end
Результат работы:
irb(main):001:0> Factory.build 'One' => #<One:0x9983d30> irb(main):002:0> Factory.build 'Two' => #<Two:0x99602cc>
Java
Исходный текст на языке Java// Product abstract class Product { } // ConcreteProductA class ConcreteProductA extends Product { } // ConcreteProductB class ConcreteProductB extends Product { } // Creator abstract class Creator { public abstract Product factoryMethod(); } // У этого класса может быть любое кол-во наследников. // Для создания нужного нам объекта можно написать следующие Фабрики: ConcreteCreatorA, ConcreteCreatorB // ConcreteCreatorA class ConcreteCreatorA extends Creator { @Override public Product factoryMethod() { return new ConcreteProductA(); } } // ConcreteCreatorB class ConcreteCreatorB extends Creator { @Override public Product factoryMethod() { return new ConcreteProductB(); } } public class FactoryMethodExample { public static void main(String[] args) { // an array of creators Creator[] creators = {new ConcreteCreatorA(), new ConcreteCreatorB()}; // iterate over creators and create products for (Creator creator: creators) { Product product = creator.factoryMethod(); System.out.printf("Created {%s}\n", product.getClass()); } } }
Результат работы:
- Created {class ConcreteProductA}
- Created {class ConcreteProductB}
C++
Исходный текст на языке C++# include<iostream> # include<string> using namespace std; // Product class Product { public: virtual string getName() = 0; }; // ConcreteProductA class ConcreteProductA : public Product { public: string getName() { return "ConcreteProductA"; } }; // ConcreteProductB class ConcreteProductB : public Product { public: string getName() { return "ConcreteProductB"; } }; // Creator class Creator { public: virtual Product* factoryMethod() = 0; }; // ConcreteCreatorA class ConcreteCreatorA : public Creator { public: Product* factoryMethod() { return new ConcreteProductA(); } }; // ConcreteCreatorB class ConcreteCreatorB : public Creator { public: Product* factoryMethod() { return new ConcreteProductB(); } }; int main() { const size_t count = 2; // An array of creators Creator* creators[count] = { new ConcreteCreatorA(), new ConcreteCreatorB() }; // Iterate over creators and create products for (size_t i = 0; i < count; i++) { Product* product = creators[i]->factoryMethod(); cout << product->getName() << endl; delete product; } for (size_t i = 0; i < count; i++) delete creators[i]; return 0; }
C#
Исходный текст на языке C#using System; using System.Collections.Generic; namespace Factory { public class MainApp { public static void Main() { // an array of creators Creator[] creators = {new ConcreteCreatorA(), new ConcreteCreatorB()}; // iterate over creators and create products foreach (Creator creator in creators) { Product product = creator.FactoryMethod(); Console.WriteLine("Created {0}", product.GetType()); } // Wait for user Console.Read(); } } // Product abstract class Product { } // "ConcreteProductA" class ConcreteProductA : Product { } // "ConcreteProductB" class ConcreteProductB : Product { } // "Creator" abstract class Creator { public abstract Product FactoryMethod(); } // "ConcreteCreatorA" class ConcreteCreatorA : Creator { public override Product FactoryMethod() { return new ConcreteProductA(); } } // "ConcreteCreatorB" class ConcreteCreatorB : Creator { public override Product FactoryMethod() { return new ConcreteProductB(); } } }
JavaScript
Исходный текст на языке JavaScript// "интерфейс" Product function Product() {} // ConcreteProduct (реализация Product) function ProductA() {} ProductA.prototype = new Product(); ProductA.prototype.constructor = ProductA; function ProductB() {} ProductB.prototype = new Product(); ProductB.prototype.constructor = ProductB; // "интерфейс" Creator function Creator() { this.factoryMethod = function() {}; } // ConcreteCreator (реализация Creator) function CreatorA() { this.factoryMethod = function() { return new ProductA(); }; } CreatorA.prototype = new Creator(); CreatorA.prototype.constructor = CreatorA; function CreatorB() { this.factoryMethod = function() { return new ProductB(); }; } CreatorB.prototype = new Creator(); CreatorB.prototype.constructor = CreatorB; // использование: var creatorA = new CreatorA(); var creatorB = new CreatorB(); var productA1 = creatorA.factoryMethod(); var productA2 = creatorA.factoryMethod(); var productB1 = creatorB.factoryMethod();
PHP5
Исходный текст на языке PHP<?php interface Product { public function GetName(); } class ProductA implements Product { private $Name='ProductA'; public function GetName() { return $this->Name; } } class ProductB implements Product { private $Name='ProductB'; public function GetName() { return $this->Name; } } interface Creator { public function FactoryMethod (); } class CreatorA implements Creator { public function FactoryMethod() { return new ProductA(); } } class CreatorB implements Creator { public function FactoryMethod() { return new ProductB(); } } $creator1 = new CreatorA(); $creator2 = new CreatorB(); $count=intval($_POST['count']); if ($count==1) { $type=$creator1->FactoryMethod(); } else { if ($count<=0) { die("false"); } else { $type=array(); for($i=1;$i<=$count;$i++) { $type[]=$creator2->FactoryMethod(); } } } ?>
Delphi
Исходный текст на языке Delphiprogram FactoryMethod; {$APPTYPE CONSOLE} uses SysUtils; type // Product TProduct = class(TObject) public function GetName: string; virtual; abstract; end; // ConcreteProductA TConcreteProductA = class(TProduct) public function GetName: string; override; end; // ConcreteProductB TConcreteProductB = class(TProduct) public function GetName: string; override; end; // Creator TCreator = class(TObject) public function FactoryMethod: TProduct; virtual; abstract; end; // ConcreteCreatorA TConcreteCreatorA = class(TCreator) public function FactoryMethod: TProduct; override; end; // ConcreteCreatorB TConcreteCreatorB = class(TCreator) public function FactoryMethod: TProduct; override; end; { ConcreteProductA } function TConcreteProductA.GetName: string; begin Result := 'ConcreteProductA'; end; { ConcreteProductB } function TConcreteProductB.GetName: string; begin Result := 'ConcreteProductB'; end; { ConcreteCreatorA } function TConcreteCreatorA.FactoryMethod: TProduct; begin Result := TConcreteProductA.Create; end; { ConcreteCreatorB } function TConcreteCreatorB.FactoryMethod(): TProduct; begin Result := TConcreteProductB.Create; end; const Count = 2; var Creators: array[1..Count] of TCreator; Product: TProduct; I: Integer; begin // An array of creators Creators[1] := TConcreteCreatorA.Create; Creators[2] := TConcreteCreatorB.Create; // Iterate over creators and create products for I := 1 to Count do begin Product := Creators[I].FactoryMethod; WriteLn(Product.GetName); Product.Free; end; for I := 1 to Count do Creators[I].Free; ReadLn; end.
Литература
- Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес Приемы объектно-ориентированного проектирования. Паттерны проектирования = Design Patterns: Elements of Reusable Object-Oriented Software. — СПб: «Питер», 2007. — С. 366. — ISBN 978-5-469-01136-1 (также ISBN 5-272-00355-1)
Шаблоны проектирования Основные Порождающие Абстрактная фабрика • Объектный пул • Одиночка • Отложенная инициализация • Прототип • Строитель • Фабричный метод
Структурные Поведенческие Интерпретатор • Итератор • Команда • Наблюдатель • Посетитель • Посредник • Состояние • Стратегия • Хранитель • Цепочка обязанностей • Шаблонный метод
Блокировка с двойной проверкой • Однопоточное выполнение • Планировщик Категория:- Шаблоны проектирования
Wikimedia Foundation. 2010.