фабричный метод проектирования - PullRequest
6 голосов
/ 19 сентября 2011

Согласно книге:

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

Скажем, у меня есть класс Создателя:

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

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

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

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

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

Кто-нибудь может дать мнекакой-нибудь пример?

Ответы [ 7 ]

10 голосов
/ 19 сентября 2011

Ваш 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 для фабрики и конкретные реализациифабрика не принимает 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.Краткий трюк: если вы расширяете фабричный класс, вы используете Abstract Factory.Если вы расширяете класс методами создания, то вы используете Factory Methods.

3 голосов
/ 19 сентября 2011

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

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

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

Вы можете посетить следующие ссылки для прочтения подробнее

1 голос
/ 25 сентября 2017

Простой и короткий:

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

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

1 голос
/ 19 сентября 2011

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

(код псевдо)

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; }

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

0 голосов
/ 23 сентября 2015

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

0 голосов
/ 19 сентября 2011

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

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

0 голосов
/ 19 сентября 2011

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

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

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

...