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

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

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

Цель

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

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

Структура

Фабричный метод (Factory Method)

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

Плюсы

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

Минусы

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

Примеры

Java

<source lang="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();
    }
}

</source>

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

C++

<source lang="cpp">

  1. include<iostream>
  2. 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; } </source>

C#

<source lang="csharp">

// 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();
 }

} </source>

JavaScript

<source lang="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(); </source>

PHP5

<source lang="php"> 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)); } </source>

См. также

Литература

  • Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес Приемы объектно-ориентированного проектирования. Паттерны проектирования = 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:工厂方法

Если вам нравится SbUP.com Сайт, вы можете поддержать его - BTC: bc1qppjcl3c2cyjazy6lepmrv3fh6ke9mxs7zpfky0 , TRC20 и ещё....