Шаблоны проектирования: абстрактная фабрика против фабричного метода - PullRequest
141 голосов
/ 18 ноября 2010

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

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

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

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

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

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

Примечание:

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

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

Factory Method

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

Abstract Factory (only 1 member)

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

alt text

Вопросы:

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

Ответы [ 10 ]

133 голосов
/ 18 ноября 2010

Надеюсь, это поможет. Он описывает различные типы заводов. Я использовал Head First Design Patterns в качестве ориентира. Я использовал yuml.me для построения диаграммы.

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

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

Static Factory

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

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

Simple Factoryt

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

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

Factory Method

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

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

Abstract Factory

Пример из .NET Framework

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

Abstract Factory From .NET Framework

78 голосов
/ 18 ноября 2010

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

Разница между шаблонами, как правило, в намерении.

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

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

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

Они обычно имеют тенденцию различаться в реализации, так как Фабричный метод является хорошимдело проще, чем Абстрактная фабрика .

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

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

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

13 голосов
/ 30 июля 2016

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

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

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

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

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

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

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

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

Поскольку интерфейс только с одним методом не может быть Фабричным методом , как и Абстрактная Фабрика , , что мы называем креативныминтерфейс только с одним методом?

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

4 голосов
/ 28 апреля 2014

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

Давайте повторим определения (оба из Википедии).

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

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

Метод фабрики

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

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

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

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

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

2 голосов
/ 20 декабря 2012

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

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

Допустим, я создаю Manager, который будет обрабатывать потребности методов действий для контроллера 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 голос
/ 01 июня 2016

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


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

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

Счетчик примеров будет

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

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

0 голосов
/ 25 апреля 2018
/*
//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;
}

*/
0 голосов
/ 28 декабря 2016

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

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

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

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

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

0 голосов
/ 08 февраля 2016

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

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

0 голосов
/ 16 июня 2013

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

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

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

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

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

Другими словами, Абстрактная Фабрика ориентирована на «ЧТО» будет создано, а Фабричный метод «КАК» будет создан.

...