Паттерны проектирования: абстрактная фабрика против фабричного метода


141

Примечание. Вопросы находятся в конце сообщения.

Я прочитал другие потоки stackoverflow, касающиеся абстрактной фабрики и фабричного метода . Я понимаю цель каждого шаблона. Однако мне не совсем понятно определение.

Factory Method определяет интерфейс для создания объекта, но позволяет подклассам решать, какие из них создавать. Заводской метод позволяет классам откладывать создание экземпляров до подклассов.

Напротив, абстрактная фабрика предоставляет интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.

- Джон Феминелла

Abstract Factory выглядит очень похож на метод фабрики . Я нарисовал несколько классов UML, чтобы проиллюстрировать свою точку зрения.

Заметка:

  • Диаграмма взята с сайта www.yuml.com, поэтому они не совсем ориентированы. Но это бесплатная услуга :).
  • Диаграммы могут быть не идеальными. Я все еще изучаю шаблоны проектирования GoF .

Заводской метод:

Заводской метод

Абстрактная фабрика (только 1 участник):

Абстрактная фабрика (только 1 участник)

Абстрактная фабрика (больше участников):

альтернативный текст

Вопросы:

  1. Если у абстрактной фабрики только один создатель и один продукт, остается ли это паттерн абстрактная фабрика ? (интерфейс для создания семей)
  2. Может ли конкретный создатель Factory Method быть создан из интерфейса или он должен быть из класса? (классы откладывают экземпляры до подклассов)
  3. Если у абстрактной фабрики может быть только один создатель и один продукт, является ли единственная разница между абстрактной фабрикой и фабричным методом в том, что создателем первого является интерфейс, а создателем второго - класс?

1
Примечание. Когда я говорю об интерфейсе, я больше думал об интерфейсе Java (абстрактный класс с абстрактными виртуальными методами). Не стесняйтесь уточнить, существует ли разница между абстрактной фабрикой и фабричным методом на разных языках.

Основное отличие здесь: stackoverflow.com/questions/1001767 , хотя и не
такое

Ответы:


133

Надеюсь это поможет. В нем описаны различные типы фабрик. В качестве ссылки я использовал шаблоны проектирования Head First . Я использовал yuml.me для построения диаграммы.

Статическая фабрика

Это класс со статическим методом для создания различных подтипов продукта.

Статическая фабрика

Простая фабрика

Это класс, который может производить различные подтипы Продукта. (Это лучше, чем Static Factory. При добавлении новых типов базовый класс Product не нужно менять, только Simple Factory Class)

Простой завод

Заводской метод

Содержит один метод производства одного типа продукта, связанного с его типом. (Это лучше, чем простая фабрика, потому что тип относится к подклассу.)

Заводской метод

Абстрактная фабрика

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

Абстрактная фабрика

Пример из .NET Framework

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

Абстрактная фабрика из .NET Framework Взаимодействие с другими людьми


Является ли разница между Static Factory и Simple Factory только тем, что метод CreateProduct находится в другом классе?
Питер О'Каллаган

4
Разве не было бы яснее, если бы в случае с Factory Method было просто Product(как абстрактно), а потом Product1и Product2как сыновья? Это поможет понять, что Factory Method - это просто создание одного продукта, тогда как Abstract Factory - это более или менее совокупность Factory Method, собранных вместе в семьи.
lllllll

81

Эти два шаблона, безусловно, связаны!

Разница между паттернами обычно заключается в намерении.

Намерение из Factory Method является «Определить интерфейс для создания объекта, но пусть подклассы решить , какой класс инстанцировать. Фабричный метод позволяет в класс отложить создание экземпляра на подклассы.»

Намерение в Abstract Factory является «Обеспечение интерфейса для создания семейств связанных или зависимых объектов без указания их конкретных классов.»

Основываясь исключительно на этих заявлениях о намерениях (цитируемых GoF), я бы сказал, что действительно Factory Method в некотором смысле является «вырожденным» абстрактным Factory с семейством из одного.

Как правило, они имеют различную реализацию, поскольку Factory Method намного проще, чем Abstract Factory .

Однако они связаны также в реализации. Как отмечено в книге GoF,

AbstractFactory только объявляет интерфейс для создания продуктов. Фактически создавать их должны подклассы ConcreteProduct. Наиболее распространенный способ сделать это - определить заводской метод для каждого продукта.

В этой вики c2 также есть интересные обсуждения по этой теме.


7
Я не понимаю ни комментарий, ни голос против. Вы можете уточнить?
Дон Роби

Что ж, ответы мне кажутся риторическими ... Нет конкретного конкретного примера ... слишком широко ...
Новалис

14

Кажется, что список (отличных) вопросов OP был проигнорирован. Текущие ответы просто предлагают перефразированные определения. Поэтому я постараюсь кратко ответить на исходные вопросы.

  1. Если у абстрактной фабрики только один создатель и один продукт, остается ли это паттерн абстрактная фабрика ? (интерфейс для создания семей)

Нет . Абстрактная фабрика должна создать более одного продукта, чтобы создать «семейство связанных продуктов». Канонический пример GoF создает ScrollBar()и Window(). Преимущество (и цель) в том, что Абстрактная фабрика может применять общую тему для нескольких своих продуктов.

  1. Может ли конкретный создатель Factory Method быть создан из интерфейса или он должен быть из класса? (классы откладывают экземпляры до подклассов)

Во-первых, мы должны отметить, что ни Java, ни C # не существовали, когда GoF писал свою книгу. Использование GoF термина « интерфейс» не связано с типами интерфейсов, представленными конкретными языками. Следовательно, конкретного создателя можно создать из любого API. Важным моментом в шаблоне является то, что API использует свой собственный фабричный метод, поэтому интерфейс только с одним методом не может быть фабричным методом в большей степени, чем он может быть абстрактной фабрикой.

  1. Если у абстрактной фабрики может быть только один создатель и один продукт, является ли единственная разница между абстрактной фабрикой и фабричным методом в том, что создателем первого является интерфейс, а создателем второго - класс?

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

Но эти ответы подняли четвертый вопрос!

  1. Поскольку интерфейс только с одним методом не может быть фабричным методом в большей степени, чем он может быть абстрактной фабрикой , что мы называем творческим интерфейсом только с одним методом?

Если метод статический, его обычно называют статической фабрикой . Если метод нестатический, его обычно называют простой фабрикой . Ни один из них не является шаблоном GoF, но на практике они используются гораздо чаще!


1
Что касается композиции и наследования, я всегда задавался вопросом: нельзя ли также выполнять композицию с помощью шаблона Factory Method? Что может помешать составить или ввести клиенту нужный бетонный завод? Или это что-то уже выходит за рамки шаблона?
georaldc

1
@georaldc, из GoF (стр. 107) « Заводской метод позволяет классу откладывать создание экземпляров до подклассов». Другими словами, фабричный метод использует наследование по определению.
jaco0646

4

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

Напомним определения (оба из Википедии).

Абстрактная фабрика

Предоставьте интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.

Заводской метод

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

Оба шаблона позволяют отделить пользовательские объекты от создания необходимых экземпляров (разъединение во время выполнения), и это общий аспект. Оба шаблона позволяют создавать иерархию фабрик в соответствии с любыми конкретными потребностями, и это еще один общий аспект.

Абстрактная фабрика позволяет создавать несколько разных типов экземпляров в одном подклассе и конкретизировать поведение творений в его разных подклассах; Обычно метод Factory объявляет о создании только одного типа объекта, который может быть детализирован в соответствии с механизмом подкласса. Вот в чем разница.

Подводя итог. Предположим, что Product определяет суперкласс создаваемых объектов, а ProductA и ProductB - два разных подкласса. Следовательно, метод абстрактной фабрики будет иметь два метода: createProductA () и createProductB (), которые будут детализированы (с точки зрения шагов создания) в своих конкретных подклассах: фабричные подклассы детализируют шаги создания для двух определенных классов. создаваемых объектов.

Согласно приведенному выше примеру, Factory Method будет реализован по-разному, абстрагируясь от создания ProductA и ProductB на таком количестве фабрик (один метод на Factory), а дальнейшая специализация шагов создания будет делегирована иерархии по мере ее построения. .


2

Если бы я создал абстрагированный (на который имеется ссылка через интерфейс или абстрактный базовый класс) фабричный класс, который создает объекты, которые имеют только один метод для создания объектов, то это будет фабричный метод .

Если бы у абстрактной фабрики было более одного метода для создания объектов, то это была бы абстрактная фабрика .

Допустим, я делаю диспетчер, который будет обрабатывать потребности методов действий для контроллера MVC. Если бы у него был один метод, скажем, для создания объектов движка, которые будут использоваться для создания моделей представления, то это был бы шаблон фабричного метода. С другой стороны, если бы у него было два метода: один для создания механизмов модели представления, а другой - для создания движков модели действия (или как вы хотите называть модель, в которой метод действия содержит потребителей), то это была бы абстрактная фабрика.

public ActionResult DoSomething(SpecificActionModel model)
{
    var actionModelEngine = manager.GetActionModelEngine<SpecificActionModel>();
    actionModelEngine.Execute(SpecificActionModelEnum.Value);

    var viewModelEngine = manager.GetViewModelEngine<SpecificViewModel>();
    return View(viewModelEngine.GetViewModel(SpecificViewModelEnum.Value);
}

1

Хотя прошло много лет с тех пор, как люди из StackOverflow задавали эту проблему так же, как и в других сообщениях (самый старый относится к 2009 году), я все еще не мог найти ответ, который хотел.


Итак, я провел несколько часов исследований в сети, просмотрел примеры и пришел к выводу, что основные отличия Abstract Factory от Factory Method заключаются в

  • Намерение: согласованность или «внешний вид» : намерение Abstract Factory состоит в том, чтобы сгруппировать семейство объектов с одинаковым стилем (например, виджеты пользовательского интерфейса с одинаковым внешним видом, автомобильные детали одинакового стиля, объекты из одной ОС, и т.д.) Во многих примерах из Abstract Factory упоминается ключевая фраза «тот же внешний вид».
  • Объекты, образующие более крупный групповой объект : Abstract Factory создает семейство объектов, образующих более крупный групповой объект, а не один объект.
  • Позже добавим новый стиль : если мы продолжим использовать фабричный метод и попытаемся добавить новый набор стилей в существующую инфраструктуру, это будет болезненно. С абстрактной фабрикой все, что нам нужно сделать, это просто создать новую конкретную фабрику, которая реализует абстрактный фабричный класс.

Встречные примеры были бы

  • Запчасть для спортивного автомобиля, используемого в седане. Это несоответствие может привести к несчастным случаям.
  • Кнопка в стиле Windows в различных виджетах графического интерфейса ОС. Это ничего не сломает, но повредит пользовательскому опыту некоторых людей, таких как я.
  • Позже мы узнаем, что наше программное обеспечение должно работать при следующем обновлении ОС, для которого требуется другой набор совместимых системных объектов, сохраняя при этом обратную совместимость программного обеспечения.

Следовательно, когда конечная группа объектов должна иметь один и тот же стиль без исключения объекта, и вы хотите скрыть эту деталь «сохранения того же стиля», тогда мы должны использовать Абстрактную фабрику.


0

Насколько я понимаю значение определений абстрактных фабрик и фабричных методов, первый реализован в статическом контексте и предоставляет объект на основе входных параметров.

Второй использует уже созданный объект (семейство), реализующий интерфейс фабричного метода. Затем фабричный метод создает конкретный экземпляр, связанный с исходным объектом, независимо от того, какой это объект.

Обычно это приводит к использованию обоих шаблонов вместе, где на первом этапе вы создаете некий общий объект, который описывает семейство связанных объектов. Вызывается статическим методом getInstance ("моя фамилия") методом. Реализация такого метода getInstance решает, какой объект семейства будет создан.

Затем я вызываю метод createProduct () для вновь созданного объекта семейства, и в зависимости от объекта семейства возвращается новый продукт.

Кажется, что эти паттерны взаимодействуют друг с другом.

Другими словами, Abstract Factory ориентирована на то, «ЧТО будет создано», и метод Factory «КАК» будет создан.


0

Все, что вам нужно помнить, это то, что абстрактная фабрика - это фабрика, которая может возвращать несколько фабрик . Итак, если у вас есть AnimalSpeciesFactory, он может возвращать такие фабрики:

Mamalfactory, BirdFactory, Fishfactory, ReptileFactory. Теперь, когда у вас есть единственная фабрика из AnimalSpeciesFactory, они используют фабричный паттерн для создания определенных объектов. Например, представьте, что у вас есть ReptileFactory из этого AnimalFactory, а затем вы можете предложить создать объекты-рептилии, такие как: змеи, черепахи, объекты-ящерицы.


0
/*
//Factory methods:

//1. Factory Method - Abstract Creator Class



#include <iostream>
#include <string.h>
using namespace std;

const std::string nineNintyCC = std::string("990CC");
const std::string thousandTwoHundredCC = std::string("1200CC");
const std::string ThousandFiveHundredCC = std::string("1500CC");
const std::string fiveThousandCC = std::string("5000CC");

// Product
class Engine
{
    public:
    virtual void packEngine() = 0;  
};

// Concrete products
// concrete product class one
class C990CCEngine: public Engine
{

    public:
    void packEngine()
    {
       cout << "Pack 990CC engine" << endl;   
    }
};

// concrete class Two
class C1200CCEngine: public Engine
{   public:
    void packEngine()
    {
        cout << "pack 1200CC engine" << endl;
    }

};

// Concrete class Three
class C1500CCEngine: public Engine
{
    public:
    void packEngine()
    {
        cout << "Pack 1500CC engine" << endl;
    }

};


// Car Factory:
class CarFactory{
    public:

    virtual Engine* createEngine(const std::string& type) = 0;
};
class Factory: public CarFactory
{
    public:
     Engine *createEngine(const std::string& type)
     {

          if(0 == nineNintyCC.compare(type))
          {    
             return new C990CCEngine;
          }
          else if(0 == thousandTwoHundredCC.compare(type))
          {
             return new C1200CCEngine;
          }
          else if(0 == ThousandFiveHundredCC.compare(type))
          {
             return new C1500CCEngine;
          } 
          else
           {
                 cout << "Invalid factory input" << endl;
             return NULL;
           }
           return NULL;
     }
};

int main()
{

    CarFactory* ptr = new Factory;
    Engine*pEngine =  ptr->createEngine(nineNintyCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    pEngine =  ptr->createEngine(ThousandFiveHundredCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    pEngine =  ptr->createEngine(thousandTwoHundredCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    pEngine = ptr-> createEngine(fiveThousandCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    return 0;
}

*/
/*
//
// interface product
#include <iostream>
#include <string>
using namespace std;

class Engine
{
 public:
 virtual void EngineType() = 0;

};

// concrte product
class AltoEngine: public Engine
{
  public:
  void EngineType()
  {
      cout << "Alto Engine" << endl;
  }
};

//Concrte product
class SwiftEngine : public Engine
{
    public:
    void EngineType()
    {
        cout << "Swift Engine" << endl;    
    }
};

class Body
{
   public:
    virtual void bodyType() = 0;

};

class AltoBody: public Body
{
  public:  
    virtual void bodyType()
    {
        cout << "Alto Car Body" << endl;
    }
};

class SwiftBody : public Body
{
    public:
    void bodyType()
    {
        cout << "SwiftCar Body" << endl;
    }

};


class CarFactory
{
   public:
   virtual Engine* createEngineProduct() = 0;
   virtual Body*   createBodyPoduct() = 0;
};
class AltoCarFactory: public CarFactory
{
    public:
    Engine * createEngineProduct()
    {
        return new AltoEngine;
    }
    Body* createBodyPoduct()
    {
        return new AltoBody;
    }

};

class SwiftCarFactory: public CarFactory
{
    public:
    Engine * createEngineProduct()
    {
        return new SwiftEngine;
    }
    Body* createBodyPoduct()
    {
        return new SwiftBody;
    }

};

int main()
{

    CarFactory* pAltoFactory = new AltoCarFactory;
    Engine* pAltoEngine = pAltoFactory->createEngineProduct();
    pAltoEngine->EngineType();
    Body* pAltoBody = pAltoFactory->createBodyPoduct();
    pAltoBody->bodyType();



    CarFactory* pSwiftFactory = NULL;
    pSwiftFactory = new SwiftCarFactory;
    Engine* pSwiftEngine = pSwiftFactory->createEngineProduct();
    pSwiftEngine->EngineType();
    Body* pSwfitBody = pSwiftFactory->createBodyPoduct();
    pSwfitBody->bodyType();
    delete pAltoBody;
    delete pAltoFactory;
    delete pSwfitBody;
    delete pSwiftFactory;
    return 0;
}
*/

/*

// One more Factory example;

#include <iostream>
#include <string>
using namespace std;

const std::string maruthi = std::string("Maruthi");
const std::string fiat = std::string("Fiat");
const std::string renault = std::string("Renault");
// Interface
class CarEngine
{
 public:
    virtual void engineType() = 0;
};

// Concrete class
class FiatEngine: public CarEngine
{
  public:
  void engineType()
  {
      cout << "Fait Engine Engine" << endl;
  }

};
// ConcreteClass
class RenaultEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Renault Engine" << endl;
    }

};
// Concrete class
class MaruthiEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Maruthi Engine" << endl;
    }
};


// Factory
class CarFactory
{
    public:
    virtual CarEngine* createFactory(const std::string&) = 0;
};

// EngineFactory
class CarEngineFactory : public CarFactory
{
     public:
     CarEngine* createFactory(const std::string&  type)
     {
          if(0 == maruthi.compare(type))
          {
              return new MaruthiEngine;

          }
          else if(0 == fiat.compare(type))
          {
              return  new FiatEngine;
          }
          else if(0 == renault.compare(type))
          {
              return new RenaultEngine;
          }
          else
          {
              cout << "Invalid Engine type" << endl;
              return NULL;
          }
     }

  };

int main()
{
    CarFactory* pCarFactory = new CarEngineFactory;
    CarEngine* pMaruthiCarEngine = pCarFactory->createFactory(maruthi);
    pMaruthiCarEngine->engineType();

    CarEngine* pFiatCarEngine = pCarFactory->createFactory(fiat);
    pFiatCarEngine->engineType();


    CarEngine* pRenaultCarEngine = pCarFactory->createFactory(renault);
    pRenaultCarEngine->engineType();

    return 0;
}


*/


/*

// One more Factory example;

#include <iostream>
#include <string>
using namespace std;

const std::string maruthi = std::string("Maruthi");
const std::string fiat = std::string("Fiat");
const std::string renault = std::string("Renault");


// Interface
class CarEngine
{
 public:
    virtual void engineType() = 0;
};

// Concrete class
class FiatEngine: public CarEngine
{
  public:
  void engineType()
  {
      cout << "Fait Car Engine" << endl;
  }

};

// ConcreteClass
class RenaultEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Renault Car Engine" << endl;
    }

};

// Concrete class
class MaruthiEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Maruthi Car Engine" << endl;
    }
};

// Interface
class CarBody
{
 public:
    virtual void bodyType() = 0;
};

// Concrete class
class FiatBody: public CarBody
{
  public:
  void bodyType()
  {
      cout << "Fait car Body" << endl;
  }

};

// ConcreteClass
class RenaultBody : public CarBody
{
    public:
    void bodyType()
    {
        cout << "Renault Body" << endl;
    }

};

// Concrete class
class MaruthiBody : public CarBody
{
    public:
    void bodyType()
    {
        cout << "Maruthi body" << endl;
    }
};


// Factory
class CarFactory
{
    public:
    virtual CarEngine* createCarEngineProduct() = 0;
    virtual CarBody* createCarBodyProduct() = 0;
};

// FiatFactory
class FaitCarFactory : public CarFactory
{
     public:
     CarEngine* createCarEngineProduct()
     {
        return new FiatEngine; 
     }
     CarBody* createCarBodyProduct()
     {
         return new FiatBody;
     }
};

// Maruthi Factory
class MaruthiCarFactory : public CarFactory
{
     public:
     CarEngine* createCarEngineProduct()
     {
         return new MaruthiEngine;
     }
     CarBody* createCarBodyProduct()
     {
         return new MaruthiBody;
     }

};

// Renault Factory
class RenaultCarFactory : public CarFactory
{
     public:
    CarEngine* createCarEngineProduct()
    {
        return new RenaultEngine;
    }

    CarBody* createCarBodyProduct()
    {
        return new RenaultBody;
    }

};


int main()
{

   // Fiat Factory
   CarFactory* pFiatCarFactory = new FaitCarFactory;
   CarEngine* pFiatEngine = pFiatCarFactory->createCarEngineProduct();
   CarBody*  pFiatBody = pFiatCarFactory->createCarBodyProduct();
   pFiatEngine->engineType();
   pFiatBody->bodyType();

   // Renault Car Factory
    return 0;
}

*/

-1

Шаблон фабричного метода - это шаблон творческого проектирования, который занимается созданием объектов без указания точного класса создаваемого объекта. Этот шаблон проектирования в основном позволяет классу откладывать создание экземпляра до подклассов.

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

во время поиска в Google я подошел к следующему блогу, который блестяще объяснил оба шаблона дизайна. взгляни на эти

http://simpletechtalks.com/factory-design-pattern/

http://simpletechtalks.com/abstract-factory-design-pattern/

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.