Фабричный метод (шаблон проектирования)

Материал из Seo Wiki - Поисковая Оптимизация и Программирование

Перейти к: навигация, поиск

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

Содержание

Цель

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

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

Структура

Файл:FactoryMethodPattern.png

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

Плюсы

  • позволяет сделать код создания объектов более универсальным, не привязываясь к конкретным классам (ConcreteProduct), а оперируя лишь общим интерфейсом (Product);
  • позволяет установить связь между параллельными иерархиями классов.

Минусы

  • необходимость создавать наследника Creator для каждого нового типа продукта (ConcreteProduct).

Примеры

Java

 public class FactoryMethodExample
 {
     public static void main(String[] args)
     {
         // an array of creators
         Creator[] creators = new Creator[2];
         creators[0] = new ConcreteCreatorA();
         creators[1] = new ConcreteCreatorB();
 
         // iterate over creators and create products
         for (Creator creator: creators)
         {
             Product product = creator.factoryMethod();
             System.out.printf("Created {%s}\n", product.getClass());
         }
     }
 }
 
 // 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();
     }
 }

Результат работы:
Created {class ConcreteProductA}
Created {class ConcreteProductB}

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 int size = 2;
	// An array of creators
	Creator* creators[size];
      creators[0] = new ConcreteCreatorA();
      creators[1] = new ConcreteCreatorB();    
 
 
	// Iterate over creators and create products
	for(int i=0;i<size;i++){
		Product* product = creators[i]->FactoryMethod();
		cout<<product->getName()<<endl;
		delete product;
	}
 
	int a;
	cin>>a;
 
	for(int i=0;i<size;i++){
		delete creators[i];
	}
	return 0;
}

C#

// Factory Method pattern -- Structural example 
 
using System;
 
class MainApp
{
  static void Main()
  {
    // An array of creators
    Creator[] creators = new Creator[2];
    creators[0] = new ConcreteCreatorA();
    creators[1] = new ConcreteCreatorB();
 
    // Iterate over creators and create products
    foreach(Creator creator in creators)
    {
      Product product = creator.FactoryMethod();
      Console.WriteLine("Created {0}",
        product.GetType().Name);
    }
 
    // 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

// "интерфейс" 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

abstract class User{
 
	function __construct($name){
	$this->name = $name;
	}
 
	function getName(){
	return $this->name;
	}
 
	// Permission methods
	function hasReadPermission(){
	return true;
	}
 
	function hasModifyPermission(){
	return false;
	}
 
	function hasDeletePermission(){
	return false;
	}
 
	// Customization methods
	function wantsFlashInterface(){
	return true;
	}
 
	protected $name = NULL;
}
 
class GuestUser extends User {
}
 
class CustomerUser extends User {
	function hasModifyPermission(){
	return true;
	}
}
 
class AdminUser extends User {
	function hasModifyPermission(){
	return true;
	}
 
	function hasDeletePermission(){
	return true;
	}
 
	function wantsFlashInterface(){
	return false;
	}
}
 
class UserFactory {
	private static $users = array("Andi"=>"admin", "Stig"=>"guest", "Derick"=>"customer");
 
	static function Create($name){
		if(!isset(self::$users[$name])){
		// Error out because the user doesn't exist
		}
		switch(self::$users[$name]){
		case "guest": return new GuestUser($name);
		case "customer": return new CustomerUser($name);
		case "admin": return new AdminUser($name);
		default: // Error out because the user kind doesn't exist
		}
	}
}
 
function boolToStr($b){
	if($b == true){
	return "Yes\n";
	}
	else{
	return "No\n";
	}
}
 
function displayPermissions(User $obj){
	print $obj->getName()."'s permissions:\n";
	print "Read: ".boolToStr($obj->hasReadPermission());
	print "Modify: ".boolToStr($obj->hasModifyPermission());
	print "Delete: ".boolToStr($obj->hasDeletePermission());
}
function displayRequirements(User $obj){
	if ($obj->wantsFlashInterface()) {
	print $obj->getName()." requires Flash\n";
	}
}
 
$logins = array("Andi", "Stig", "Derick");
 
foreach($logins as $login){
	displayPermissions(UserFactory::Create($login));
	displayRequirements(UserFactory::Create($login));
}

См. также

Литература

  • Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес Приемы объектно-ориентированного проектирования. Паттерны проектирования = Design Patterns: Elements of Reusable Object-Oriented Software. — СПб: «Питер», 2007. — С. 366. — ISBN 978-5-469-01136-1 (также ISBN 5-272-00355-1)



порождающие шаблоны проектирования
абстрактная фабрика | строитель | фабричный метод | прототип | одиночка | отложенная инициализация
bg:Метод Фабрика (шаблон)

ca:Factory method de:Fabrikmethode en:Factory method pattern es:Factory Method (patrón de diseño) fr:Fabrique (patron de conception) he:תבנית Factory Method it:Factory method ja:Factory Method パターン ko:팩토리 메서드 패턴 ml:ഫാക്ടറി മെത്തേഡ് പാറ്റേൺ nl:Factory (ontwerppatroon) pl:Metoda wytwórcza (wzorzec projektowy) pt:Factory Method th:แฟกทอรีเมธอดแพตเทิร์น uk:Фабричний метод (шаблон проектування) vi:Factory method pattern zh:工厂方法

Личные инструменты

Served in 0.296 secs.