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

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

Я прочитал другие потоки stackoverflow относительно абстрактный завод против Заводского метода. Я понимаю смысл каждого узора. Однако я не совсем понимаю это определение.

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

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

-Джон Feminella

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

Примечание:

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

Способ Завода:

Factory Method

абстрактная Фабрика (только 1):

Abstract Factory (only 1 member)

абстрактная Фабрика (подробнее участники):

alt text

вопросы:

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

10 ответов


надеюсь, что это помогает. В ней описываются различные типы фабрик. Я использовал Головы Первый Дизайн Шаблоны как моя ссылка. Я использовал yuml.я к диаграмме.

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

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

Static Factory

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

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

Simple Factoryt

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

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

Factory Method

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

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

Abstract Factory

пример из .NET Framework

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

Abstract Factory From .NET Framework ​​​


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

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

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

на намерение of Абстрактная Фабрика is " предоставляет интерфейс для создания семейств родственные или зависимые объекты без указания их конкретных классов."

основываясь исключительно на этих заявлениях о намерениях (цитата из GoF), я бы сказал, что действительно Метод Фабрики в некотором смысле "дегенерат"Абстрактная Фабрика С семьей из одного человека.

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

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

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

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


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

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

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

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

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

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

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

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

  1. С, интерфейс с одним методом не может быть Метод Фабрики больше, чем это может быть Абстрактная Фабрика, то, что мы называем creational интерфейс только с одним методом?

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


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

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

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

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

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

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

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

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

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

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


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

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

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

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

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


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

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

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

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

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


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

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

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

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

кажется, что эти шаблоны сотрудничают друг с другом.

другими словами абстрактная Фабрика ориентирован на "что" будет создаваться и заводским методом" как " будет создаваться.


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

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


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

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

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

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

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


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

*/