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

согласно Книге:

суть шаблона фабрики состоит в том, чтобы "определить интерфейс для создание объекта, но пусть подклассы решают, какой класс создать экземпляр. Метод Factory позволяет классу отложить создание экземпляра до подклассы.

скажем, у меня есть класс Creator:

class Product; //this is what the Factory Method should return
class Creator {
    public:
        Creator()   //ctor
        { //... }

        virtual Product make(//args)
        { //... }
}

хорошо, это мой класс Создателя, но я не понимаю

метод Factory позволяет классу отложить создание экземпляра до подклассы

какое это имеет отношение к подклассам? И для чего я должен использовать подклассы?

кто-нибудь может привести мне пример?

7 ответов


код Creator класс фабрика. Назовем это ProductFactory, чтобы сделать пример более явным.

(я предполагаю, что вы используете c++)

class Book : public Product
{
};

class Computer : public Product
{
};

class ProductFactory
{
public:
  virtual Product* Make(int type)
  {
    switch (type)
    {
      case 0:
        return new Book();
      case 1:
        return new Computer();
        [...]
    }
  }
}

назовем это так:

ProductFactory factory = ....;
Product* p1 = factory.Make(0); // p1 is a Book*
Product* p2 = factory.Make(1); // p2 is a Computer*
// remember to delete p1 and p2

Итак, чтобы ответить на ваш вопрос:

какое это имеет отношение к подклассам? И что я должен использовать подклассы?

что определение для картины фабрики говорит что фабрика определяет общий API для создания экземпляров определенного типа (обычно интерфейс или абстрактный класс), но реальный тип возвращаемых реализаций (таким образом, ссылка подкласса) является ответственностью фабрики. В этом примере фабрика возвращает Product экземпляры, для которых Book и Computer действительны подклассы.

есть и другие идиомы для фабрики, такие как наличие API для фабрики и конкретных реализаций фабрики do не принять type как в моем примере, но они связаны с типом возвращаемых экземпляров, например:

class ProductFactory
{
public:
  virtual Product* Make() = 0;
}

class BookProductFactory : public ProductFactory
{
public:
    virtual Product* Make()
    {
      return new Book();
    }
}

в этом классе BookProductFactory всегда возвращает Book экземпляров.

ProductFactory* factory = new BookProductFactory();
Product* p1 = factory->Make(); // p1 is a Book
delete p1;
delete factory;

чтобы было ясно, так как, кажется, есть немного путаницы между Abstract Factory и Factory method шаблоны проектирования, давайте посмотрим конкретный пример:

Использование Абстрактной Фабрики

class ProductFactory {
protected:
  virtual Product* MakeBook() = 0;
  virtual Product* MakeComputer() = 0;
}

class Store {
public:
   Gift* MakeGift(ProductFactory* factory) {
     Product* p1 = factory->MakeBook();
     Product* p2 = factory->MakeComputer();
     return new Gift(p1, p2);
   }
}

class StoreProductFactory : public ProductFactory {
protected:
  virtual Product* MakeBook() { return new Book(); }
  virtual Product* MakeComputer() { return new Computer(); }
}

class FreeBooksStoreProductFactory : public StoreProductFactory {
protected:
  virtual Product* MakeBook() {
    Book* b = new FreeBook(); // a FreeBook is a Book with price 0
    return b;
  }
}

это используется как это:

Store store;
ProductFactory* factory = new FreeBooksStoreProductFactory();
Gift* gift = factory->MakeGift(factory);
// gift has a FreeBook (Book with price 0) and a Computer
delete gift;
delete factory;

использование заводского метода

class Store {
public:
   Gift* MakeGift() {
     Product* p1 = MakeBook();
     Product* p2 = MakeComputer();
     return new Gift(p1, p2);
   }

 protected:
   virtual Product* MakeBook() {
     return new Book();
   }

   virtual Product* MakeComputer() {
     return new Computer();
   }
}

class FreeBooksStore : public Store {
protected:
  virtual Product* MakeBook() {
    Book* b = new FreeBook(); // a FreeBook is a Book with price 0
    return b;
  }
}

это используется следующим образом:

Store* store = new FreeBooksStore();
Gift* gift = store->MakeGift();
// gift has a FreeBook (Book with price 0) and a Computer
delete gift;
delete store;

при использовании type дискриминатор, как я сделал в исходном примере, мы используем parametized factory methods - метод, который знает, как создавать различные виды объектов. Но это может появиться в любом Abstract Factory или Factory Method узор. Краткий трюк: если вы расширяете класс factory, вы используете абстрактную фабрику. Если вы расширяете класс с помощью методов создания, то вы используете заводские методы.


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

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

например WebRequest.Создать("http://www.example.com") вернет мне HttpWebRequest, но WebRequest.Создать("ftp://www.example.com") вернет мне FtpWebRequest, потому что оба имеют разные протоколы, которые реализованы разными классами, но открытый интерфейс одинаков, поэтому это решение не должно приниматься потребителем моего API.


Product Make () сделает правильный тип (подкласс) продукта на основе определенных условий и "отложит" фактический экземпляр до конкретных продуктов.

(код psuedo)

public class Product
{
    public static Product Make()
    {
        switch(day_of_week)
        {
           case Monday: return new Honey(1.1);
           case Wednesday: return new Milk(3.6);
           case Thurday: return new Meat(0.5);
           case Friday: return new Vegetable(1.3);
           case Saturday: return new Vegetable(2.3); // more expensive on saturday, only factory need to know
           default: return null; // off day!
        }
    }

    // returns price based on underlying product type and hidden/auto conditions (days of week)
    public virtual void GetPrice() { return Price; }

    // sometimes a factory can accept a product type enum
    // From API POV, this is easier at a glance to know avaliable types.
    pubic enum Type { Milk, Honey, Meat, Vegetable };

    public static Product Make(Type, Day)
    {
        // create the specified type for the specified day.
    }
}

public class Honey : Product { Price = arg; }
public class Milk : Product { Price = arg; }
public class Meat : Product { Price = arg; }
public class Vegetable : Product { Price = arg; }

Factory скрывает необходимые условные данные для построения различных типов продуктов. Во-вторых, IMHO, с точки зрения пользователя API, обычно легче увидеть, какие типы продуктов есть (обычно из перечисления), и легче создать их с одной точки создание.


просто и коротко:

на завод, проверяется, какой" подкласс " запрашивается для создания экземпляра so "let the subclasses decide which class to instantiate"
(вы используете условные операторы в Заводском классе, где должно быть принято решение.)

"define an interface or abstract class for creating an object". очевидно, что вы храните объект в ссылке интерфейса, и клиент не знает, какой объект конкретного класса возвращается. (таким образом, вы определили интерфейс для создания объекта).


Я могу только предположить, что он имеет в виду это:

class Product; //this is what the Factory Method should return
class Box : Product;

class Creator {
    public:
        Creator()   //ctor
        { //... }

        virtual Product* make(//args) = 0;
};

class BoxCreator{
    public:
        BoxCreator()
        {}
        virtual Product* make()
        {}
};

Creator* pCreator = new BoxCreator;
Product* pProduct = pCreator->make(); //will create a new box

однако это не стандартный способ создания фабрики.


предоставление таких примеров в псевдо-коде немного запутанно, шаблон очень зависит от языка. Ваш пример выглядит как в C++, но он недействителен в C++, потому что make возвращает Product по значению. Это полностью противоречит главной цели Factory - для возврата ссылки (указателя в случае C++) на базовый класс. Некоторые ответы принимают это как C# или Java (я думаю), когда другие как c++.

Factory шаблон опирается на полиморфизм. Ключевым моментом является возврат ссылки на base Product класса. Дети Factory создаст экземпляры конкретных классов.


У меня такая же путаница "пусть подклассы решают, какой класс создавать" - потому что в реализации Заводского метода с использованием new Для создания объекта " - я ссылаюсь на первую книгу шаблонов дизайна, в которой четко указано об этом следующим образом - "Как и в официальном определении, вы часто услышите, что разработчики говорят, что пусть подкласс решает, какой класс создавать .Они говорят "решает" не потому, что шаблон позволяет подклассу самим решать время выполнения, а потому, что создатель класс пишется без знания фактического продукта, который будет создан, что определяется исключительно выбором подкласса, который используется "