Padrões de design: Fábrica abstrata versus método de fábrica


141

Nota: as perguntas estão no final da postagem.

Eu li os outros threads de stackoverflow sobre Abstract Factory vs Factory Method . Eu entendo a intenção de cada padrão. No entanto, não estou claro sobre a definição.

O Método de Fábrica define uma interface para criar um objeto, mas permite que as subclasses decidam quais delas serão instanciadas. Um método de fábrica permite que as classes adiem a instanciação para subclasses.

Por outro lado, um Abstract Factory fornece uma interface para criar famílias de objetos relacionados ou dependentes sem especificar suas classes concretas.

- John Feminella

A Fábrica Abstrata é muito parecida com o Método de Fábrica . Eu desenhei algumas classes UML para ilustrar meu argumento.

Nota:

  • O diagrama é de www.yuml.com, portanto, não estão perfeitamente orientados. Mas é um serviço gratuito :).
  • Os diagramas podem não ser perfeitos. Ainda estou aprendendo os padrões de design do GoF .

Método de fábrica:

Método de fábrica

Fábrica abstrata (apenas 1 membro):

Fábrica abstrata (apenas 1 membro)

Fábrica abstrata (mais membros):

texto alternativo

Questões:

  1. Se a Abstract Factory tem apenas um criador e um produto, ainda é o padrão da Abstract Factory ? (uma interface para criar famílias)
  2. O criador concreto do Método de Fábrica pode ser criado a partir de uma Interface ou precisa ser de uma classe? (as classes adiam instanciações para subclasses)
  3. Se a Abstract Factory pode ter apenas um criador e um produto, a única diferença entre a Abstract Factory e o Factory Method é que o criador do primeiro é uma interface e o criador do último é uma classe?

1
Nota: Quando me refiro à Interface, pensei mais nos termos de uma Interface Java (classe abstrata com métodos virtuais abstratos). Sinta-se à vontade para esclarecer se existe uma diferença entre a Abstract Factory e o Factory Method em diferentes idiomas.

A diferença básica aqui: stackoverflow.com/questions/1001767 , embora não tão específico como você está perguntando ..
Nawfal

Respostas:


134

Espero que isto ajude. Descreve os vários tipos de fábricas. Eu usei Head First Design Patterns como minha referência. Eu usei o yuml.me para fazer o diagrama.

Fábrica estática

É uma classe com um método estático para produzir vários subtipos de produtos.

Fábrica estática

Fábrica Simples

É uma classe que pode produzir vários subtipos de produto. (É melhor que a Static Factory. Quando novos tipos são adicionados, a classe base do produto não precisa ser alterada apenas a classe Simple Factory)

Fábrica simples

Método de fábrica

Contém um método para produzir um tipo de produto relacionado ao seu tipo. (É melhor que uma Fábrica Simples, porque o tipo é adiado para uma subclasse.)

Método de fábrica

Fábrica abstrata

Produz uma família de tipos relacionados. É visivelmente diferente de um Método de Fábrica, pois possui mais de um método de tipos que produz. (Isso é complicado, consulte o próximo diagrama para obter um exemplo melhor da vida real).

Fábrica abstrata

Exemplo do .NET Framework

DbFactoriesProvider é uma Fábrica Simples, pois não possui subtipos. O DbFactoryProvider é uma fábrica abstrata, pois pode criar vários objetos de banco de dados relacionados, como objetos de conexão e comando.

Fábrica abstrata do .NET Framework O que outras pessoas estão dizendo


A diferença entre a Static Factory e a Simple Factory é que o método CreateProduct está dentro de uma classe diferente?
Peter O'Callaghan

4
Não seria mais claro se, no caso do Método de Fábrica, havia apenas Product(como um resumo), e então Product1e Product2, como filhos? Isso ajudaria a afirmar que o Método de Fábrica é apenas criar um produto, enquanto o Abstract Factory é mais ou menos um monte de Métodos de Fábrica reunidos em famílias.
lllllll

79

Os dois padrões estão certamente relacionados!

A diferença entre os padrões geralmente é intencional.

A intenção do Factory Method é "Definir uma interface para criar um objeto, mas deixe as subclasses decidirem qual classe instanciar. O Factory Method permite que uma classe adie a instanciação para subclasses".

A intenção do Abstract Factory é "Fornecer uma interface para criar famílias de objetos relacionados ou dependentes sem especificar suas classes concretas".

Baseado puramente nessas declarações de intenção (citadas no GoF), eu diria que, de fato, o Método Fábrica é, em certo sentido, uma Fábrica Abstrata "degenerada" com uma família de um.

Eles geralmente tendem a diferir na implementação, pois o Método de Fábrica é muito mais simples que o Abstract Factory .

No entanto, eles também estão relacionados à implementação. Conforme observado no livro do GoF,

AbstractFactory declara apenas uma interface para a criação de produtos. Cabe às subclasses ConcreteProduct realmente criá-las. A maneira mais comum de fazer isso é definir um método de fábrica para cada produto.

Este wiki c2 também tem uma discussão interessante sobre esse tópico.


7
Eu não entendo nem o comentário nem o voto negativo. Você pode elaborar?
Don Roby

Bem, as respostas me parece retórica ... No exemplo concreate real ... excessivamente ampla ...
Novalis

14

Parece que a lista de perguntas (excelentes) do OP foi ignorada. As respostas atuais meramente oferecem definições reformuladas. Por isso, tentarei abordar as questões originais de forma concisa.

  1. Se a Abstract Factory tem apenas um criador e um produto, ainda é o padrão da Abstract Factory ? (uma interface para criar famílias)

Não . Uma Fábrica Abstrata deve criar mais de um produto para criar uma "família de produtos relacionados". O exemplo canônico do GoF cria ScrollBar()e Window(). A vantagem (e a finalidade) é que a Abstract Factory pode aplicar um tema comum em seus múltiplos produtos.

  1. O criador concreto do Método de Fábrica pode ser criado a partir de uma Interface ou precisa ser de uma classe? (as classes adiam instanciações para subclasses)

Primeiro, devemos observar que nem Java nem C # existiam quando o GoF escreveu seu livro. O uso GoF do termo interface não está relacionado aos tipos de interface introduzidos por idiomas específicos. Portanto, o criador concreto pode ser criado a partir de qualquer API. O ponto importante no padrão é que a API consome seu próprio Método de Fábrica, portanto, uma interface com apenas um método não pode ser um Método de Fábrica mais do que uma Fábrica Abstrata.

  1. Se a Abstract Factory pode ter apenas um criador e um produto, a única diferença entre a Abstract Factory e o Factory Method é que o criador do primeiro é uma interface e o criador do último é uma classe?

Esta pergunta não é mais válida, seguindo as respostas acima; no entanto, se você continuar pensando que a única diferença entre o Abstract Factory e o Factory Method é o número de produtos criados, considere como um cliente consome cada um desses padrões. Uma fábrica abstrata é normalmente injetada em seu cliente e invocada por meio de composição / delegação. Um método de fábrica deve ser herdado. Então, tudo volta ao antigo debate sobre composição versus herança.

Mas essas respostas levantaram uma quarta pergunta!

  1. Como uma interface com apenas um método não pode ser um Método de Fábrica, assim como não pode ser uma Fábrica Abstrata , o que chamamos de interface criacional com apenas um método?

Se o método for estático, normalmente é chamado de Static Factory . Se o método não for estático, geralmente é chamado de Fábrica Simples . Nenhum deles é um padrão GoF, mas na prática eles são muito mais usados!


1
Sobre composição versus herança, sempre me perguntei: não é possível também fazer composição com o padrão Factory Method? O que impediria alguém de compor ou injetar a fábrica de concreto correta em um cliente? Ou isso já está fora do escopo do padrão?
21817 georaldc #

1
@georaldc, do GoF (página 107) "O Factory Factory permite que uma classe adie a instanciação para subclasses. " Em outras palavras, o Factory Method usa herança por definição.
jaco0646

4

Na minha opinião, a ligeira diferença entre os dois padrões reside na aplicabilidade e, como já foi dito, no Intent .

Vamos recapitular as definições (ambas da Wikipedia).

Fábrica abstrata

Forneça uma interface para criar famílias de objetos relacionados ou dependentes sem especificar suas classes concretas.

Método de fábrica

Defina uma interface para criar um objeto , mas deixe as classes que implementam a interface decidirem qual classe instanciar . O método Factory permite que uma classe adie a instanciação para subclasses.

Ambos os padrões permitem dissociar os objetos do usuário da criação de instâncias necessárias (dissociação em tempo de execução), e esse é o aspecto comum. Ambos os padrões permitem criar uma hierarquia de fábricas de acordo com quaisquer necessidades específicas, e esse é outro aspecto comum.

Abstract Factory permite criar vários tipos diferentes de instâncias em uma subclasse e particularizar o comportamento das criações em suas diferentes subclasses; normalmente, o método Factory declara a criação de apenas um tipo de objeto que pode ser particularizado de acordo com o mecanismo de subclassificação. Essa é a diferença.

Resumindo. Digamos que Product defina a superclasse dos objetos de criação e que ProductA e ProductB são duas subclasses diferentes. Portanto, o método Abstract Factory terá dois métodos, createProductA () e createProductB (), que serão particulares (em termos de etapas de criação) em suas subclasses específicas: as subclasses de factory especificam as etapas de criação para as duas classes definidas de objetos em criação.

De acordo com o exemplo acima, o Método de Fábrica será implementado de maneira diferente, abstraindo a criação do Produto A e do Produto B em tantas fábricas (um método por Fábrica), e a especialização adicional das etapas de criação será delegada na hierarquia à medida que for criada .


2

Se eu criasse uma classe Factory abstraída (referenciada por meio de uma interface ou classe base abstrata) que crie objetos que possuam apenas um método para criar objetos, seria um método Factory .

Se a Fábrica abstraída tivesse mais de um método para criar objetos, seria uma Fábrica Abstrata .

Digamos que eu crie um gerente que lide com as necessidades dos métodos de ação de um controlador MVC. Se houvesse um método, digamos, para criar os objetos de mecanismo que serão usados ​​para criar modelos de vista, seria um padrão de método de fábrica. Por outro lado, se houvesse dois métodos: um para criar mecanismos de modelo de exibição e outro para criar mecanismos de modelo de ação (ou o que você quiser chamar de modelo que o método de ação contém consumidores), seria uma fábrica abstrata.

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

Embora já se passaram muitos anos desde que as pessoas do StackOverflow questionaram esse problema da mesma forma em outras postagens (a mais antiga vai até 2009), ainda não consegui encontrar a resposta que queria.


Então, eu fiz algumas horas pesquisando na web, revisando os exemplos e cheguei a essa conclusão, as principais diferenças entre o Abstract Factory e o Factory Method são

  • A intenção: coerência ou "aparência e aparência" : a intenção da Abstract Factory é agrupar uma família de objetos com o mesmo estilo (por exemplo, os mesmos widgets de interface do usuário com aparência e aparência, peças de carro com o mesmo estilo, objetos de um mesmo sistema operacional, etc.) Muitos exemplos da Abstract Factory mencionam a frase-chave "a mesma aparência".
  • Objetos que formam um objeto de grupo maior : Abstract Factory cria uma família de objetos que formam um objeto de grupo maior, não um objeto único.
  • Posteriormente, adicione um novo estilo : se continuássemos usando o Método de Fábrica e tentássemos adicionar um novo conjunto de estilos à infraestrutura existente, seria doloroso. Com a Abstract Factory, tudo o que precisamos fazer é simplesmente criar uma nova fábrica de concreto que implemente a classe abstrata de fábrica.

Os exemplos contrários seriam

  • Uma peça do carro esportivo usado em um sedan. Essa inconsistência pode levar a acidentes.
  • Um botão no estilo Windows em diferentes widgets da GUI do SO. Não vai quebrar nada, mas prejudicar a experiência do usuário para algumas pessoas, como eu.
  • Mais tarde, descobrimos que nosso software precisa ser executado na próxima atualização do sistema operacional, que precisa de um conjunto diferente de objetos de sistema compatíveis, mantendo o software compatível com versões anteriores.

Portanto, quando um grupo de objetos final deve ter o mesmo estilo sem uma exceção de um objeto e você deseja ocultar esse detalhe "mantendo o mesmo estilo", devemos usar o Abstract Factory.


0

Tanto quanto eu entendo o significado de Fábrica abstrata e definições de método Factory, a primeira é implementada em contexto estático e fornece objeto com base em parâmetros de entrada.

O segundo usa o objeto já criado (a família) que implementa a interface do método de fábrica. O método de fábrica cria uma instância específica relacionada ao objeto original, independentemente de qual seja.

Portanto, isso geralmente leva ao uso dos dois padrões juntos, onde na primeira etapa você cria algum objeto geral que descreve a família de objetos relacionados. É chamado pelo método estático getInstance ("nome da minha família"). A implementação desse método getInstance decide qual objeto de família será criado.

Então chamo o método createProduct () no objeto de família recém-criado e, dependendo do objeto de família, o novo produto será retornado.

Parece que esses padrões cooperam para cada um.

Em outras palavras, a Abstract Factory está focada em "O QUE" será criado e o método de fábrica "COMO" será criado.


0

Tudo o que você precisa lembrar é que uma fábrica abstrata é uma fábrica que pode devolver várias fábricas . Portanto, se você tiver um AnimalSpeciesFactory, poderá retornar fábricas como esta:

Mamalfactory, BirdFactory, Fishfactory, ReptileFactory. Agora que você possui uma única fábrica da AnimalSpeciesFactory, eles usam o padrão de fábrica para criar objetos específicos. Por exemplo, imagine que você tenha um ReptileFactory desse AnimalFactory, e poderá oferecer objetos para répteis como: Cobras, tartarugas, objetos de lagartos.


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

O padrão de método de fábrica é um padrão de design criacional que lida com a criação de objetos sem mostrar a classe exata de objeto que está sendo criado. Esse padrão de design basicamente permite que uma classe adie a instanciação para subclasses.

O padrão Abstract Factory serve para encapsular um grupo de fábricas individuais sem expor as classes concretas. Nesse modelo, uma interface genérica de uma classe abstrata de fábrica é usada para criar o objeto concreto necessário, separando os detalhes da implementação de objetos de seu uso e composição. Esse padrão de design é amplamente usado em aplicativos de GUI em que tipos semelhantes de componentes da GUI precisam ser criados.

enquanto pesquisava no google, vim seguindo o blog, que explicava os dois padrões de design de maneira brilhante. dê uma olhada neles

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

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.