Design Patterns: Abstract Factory vs Factory Metho

2019-01-03 00:38发布

Note: Questions are at the end of the post.

I have read the other stackoverflow threads regarding Abstract Factory vs Factory Method. I understand the intent of each pattern. However, I am not clear on the definition.

Factory Method defines an interface for creating an object, but lets subclasses decide which of those to instantiate. A factory method lets classes defer instantiation to subclasses.

By contrast, an Abstract Factory provides an interface for creating families of related or dependent objects without specifying their concrete classes.

-John Feminella

The Abstract Factory looks very similar to the Factory Method. I have drawn a few UML classes to illustrate my point.

Note:

  • The diagram are from www.yuml.com so they are not perfectly oriented. But its a free service :).
  • The diagrams may not be perfect. I am still learning the GoF design patterns.

Factory Method:

Factory Method

Abstract Factory (only 1 member):

Abstract Factory (only 1 member)

Abstract Factory (more members):

alt text

Questions:

  1. If the Abstract Factory has only one creator and one product, is it still the Abstract Factory pattern? (an interface for creating familes)
  2. Can the Factory Method concrete creator be created from an Interface or does it have to be from a class? (classes defer instantiations to subclasses)
  3. If the Abstract Factory can have only one creator and one product, is the only difference between the Abstract Factory and the Factory Method that the creator for the former is an Interface and the creator for the latter is a Class?

10条回答
趁早两清
2楼-- · 2019-01-03 01:01

In my opinion, the slight difference between the two patterns resides in the applicability, and so, as already said, in the Intent.

Let's recap the definitions (both from Wikipedia).

Abstract Factory

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

Factory Method

Define an interface for creating an object, but let the classes that implement the interface decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses.

Both patterns allow to decouple the user objects from creating needed instances (run-time decoupling), and this is the common aspect. Both patterns allow to create a hierarchy of factories according to any specific needs, and this is another common aspect.

Abstract Factory allows to create several different type of instances in one sub-class, and to particularize the creations behavior in its different sub-classes; normally, Factory method declares the creation of only one type of object that can be particularized according to the sub-classing mechanism. That's the difference.

By summarizing. Let's say that Product defines the super-class of the creating objects, and that ProductA and ProductB are two different sub-classes. Therefore, the Abstract Factory method will have two methods, createProductA() and createProductB() which will be particularized (in terms of creation steps) in its specific sub-classes: the factory sub-classes particularize the creation steps for the two defined classes of objects under creation.

According to the above example, the Factory Method will be implemented differently, abstracting the creation of ProductA and ProductB in as many factories (one method per Factory), and the further specialization of the creation steps will be delegated to the hierarchy as it is built.

查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-01-03 01:01

As far as I understand the meaning o Abstract factory and Factory method definitions the first one is implemented in static context and provides object based on input parameters.

Second one uses already created object (the family) which implements factory method interface. The factory method then creates specific instance related to the original object no matter which one it is.

So this usually leads to using both patterns together where in first step you create some general object which describes family of related objects. It is called by static method getInstance("my family name") method. Implementation of such getInstance method decides which family object will be created.

Then I call createProduct() method on newly created family object and depending family object the new product will be returned.

It seems that these patterns cooperate to each one.

In another words Abstract Factory is focused on "WHAT" will be created and Factory method "HOW" it will be created.

查看更多
Lonely孤独者°
4楼-- · 2019-01-03 01:10

Although, it's been many years since people from StackOverflow questioned about this issue similarly in other posts (oldest goes to 2009), I still could not find the answer I wanted.


So I did a few hours of researching through web, reviewing the examples, and came to this conclusion, the major differences of Abstract Factory from Factory Method are

  • The intention: coherence or "look-and-feel": Abstract Factory's intention is to group a family of objects with a same style (ex. same look-and-feel UI widgets, same style car parts, objects from a same OS, etc.) Many examples from Abstract Factory mentions about the key phrase "the same look-and-feel".
  • Objects forming a bigger group object: Abstract Factory creates a family of objects forming a bigger group object, not a single object.
  • Later add a new style: If we kept on using Factory Method and try to add a new set of style to existing infrastructure, it would be painful. With Abstract Factory, all we just have to do is simply create a new concrete factory that implements the abstract factory class.

The counter examples would be

  • A car part for sports car used in a sedan. This inconsistency may lead to accidents.
  • A Windows-style button in different OS GUI widgets. It's not going to break anything but hurt user experience for some people, like me.
  • Later, we find out that our software needs to run in the next OS upgrade which needs different set of compatible system objects while keeping the software backward compatible.

Therefore, when a final object group should have the same style without an exception of a object and you want to hide this "keeping the same style" detail, then we should use Abstract Factory.

查看更多
冷血范
5楼-- · 2019-01-03 01:10

Factory method pattern is a creational design pattern which deals with creating objects without showing the exact class of object that is being created. This design pattern basically allows a class to defers the instantiation to sub-classes.

The Abstract Factory pattern serves encapsulation to a group of individual factories without exposing the concrete classes. In this model, a generic interface of an abstract factory class is used to create the required concrete object separating the details of implementation of objects from their usage and composition. This design pattern is widely used in GUI applications where similar kind of GUI components needs to be created.

while searching on google i came up following blog which explained both design pattern brilliantly. have a look on these

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

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

查看更多
Anthone
6楼-- · 2019-01-03 01:10
/*
//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;
}

*/
查看更多
Luminary・发光体
7楼-- · 2019-01-03 01:13

If I created an abstracted (referenced via an interface or abstract base class) Factory Class that creates objects that has only one method to create objects, then it would be a Factory Method.

If the abstracted Factory had more than 1 method to create objects, then it would be an Abstract Factory.

Let's say I make a Manager that will handle the needs of action methods for an MVC controller. If it had one method, say to create the engine objects that will be used to create view models, then it would be an factory method pattern. On the other hand if it had two methods: one to create view model engines, and another to create action model engines (or whatever you want to call the model that the action method contains consumers), then it would be an abstract factory.

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);
}
查看更多
登录 后发表回答