Por que precisamos do padrão abstrato de design de fábrica?


124

A maior parte da definição diz:

Uma fábrica abstrata fornece uma interface para criar famílias de objetos relacionados sem especificar suas classes concretas

Para que serve o Abstract Factory Pattern, pois podemos realizar a tarefa através da criação de objetos da própria classe concreta. Por que temos um método de fábrica que cria objetos da classe Concrete?

Por favor, forneça-me algum exemplo da vida real em que devo implementar o padrão abstractFactory?

Respostas:


219

6
Todos esses exemplos descrevem o padrão de método de fábrica, porque todos eles retornam uma única interface de produto. Nada disso é um Padrão de Fábrica Abstrato, porque nenhum deles produz uma família de interfaces de produto relacionadas.
jaco0646

32
No interesse da divulgação completa, o autor desta resposta deveria ter deixado claro que ele também é o autor de todas as respostas vinculadas; portanto, esta lista NÃO é uma amostra representativa da comunidade SO.
jaco0646

1
@ jaco0646 IIRC, o padrão Factory Method é uma especialização do padrão Template Method , que depende da herança. No entanto, posso estar enganado, pois estou viajando e não tenho meu livro no GoF comigo. O que você quer dizer com "nenhum deles produz uma família de interfaces de produtos relacionadas"?
21416 Mark-Seemann

1
A pista mais simples que indica que uma fábrica não está em conformidade com o Padrão de Fábrica Abstrata é contar os produtos abstratos que ela produz (usei o termo "interfaces de produto" no lugar de "produtos abstratos" para evitar o uso excessivo da palavra "abstrato") . Uma fábrica que produz um único produto abstrato não pode ser uma Fábrica Abstrata porque, por definição, a Fábrica Abstrata produz uma família de produtos relacionados . É importante observar que essa família não se refere a diferentes implementações de uma interface, mas a produtos com interfaces relacionadas diferentes.
jaco0646

1
Aqui está um exemplo oodesign.com/abstract-factory-pattern.html . É para isso que o padrão abstrato de fábrica foi criado originalmente.
user2802557

23

Um exemplo da vida real para o uso do padrão Abstract Factory é fornecer acesso a dados para duas fontes de dados diferentes. Suponha que seu aplicativo suporte diferentes armazenamentos de dados. (por exemplo, um banco de dados SQL e um arquivo XML). Você tem duas interfaces de acesso a dados diferentes, por exemplo, IReadableStoree IWritableStoredefine os métodos comuns esperados pelo seu aplicativo, independentemente do tipo de fonte de dados utilizada.

Que tipo de fonte de dados deve ser usada não deve alterar a maneira como o código do cliente recupera suas classes de acesso a dados. Você AbstractDataAccessFactorysabe que tipo de fonte de dados está configurada e fornece uma fábrica concreta para o código do cliente, SqlDataAccessFactoryou seja, ou XmlDataAccessFactory. Essas fábricas de concreto podem criar implementações concretas, por exemplo, SqlReadableStoree SqlWriteableStore.

O DbProviderFactory no .NET Framework é um exemplo desse padrão.


18
Esta resposta pode descrever com precisão o padrão Factory Method, ou Static Factory, mas não o padrão Abstract Factory.
jaco0646

5

Se eu entendi bem - a questão é: por que temos o método Factory e os padrões abstratos de fábrica. Você precisa de fábrica abstrata quando diferentes classes polimórficas têm diferentes procedimentos de instanciação. E você deseja que algum módulo crie instâncias e as use, sem conhecer nenhum detalhe da inicialização do objeto. Por exemplo - você deseja criar objetos Java fazendo alguns cálculos. Mas alguns deles fazem parte do aplicativo, enquanto o bytecode de outros deve ser lido no banco de dados. Por outro lado - por que precisamos do método de fábrica? Concordo, essa fábrica abstrata se sobrepõe. Mas, em alguns casos - é muito menos código para escrever, ter menos classes e interfaces facilita a compreensão do sistema.


3

Para que serve o Abstract Factory Pattern, pois podemos realizar a tarefa através da criação de objetos da própria classe concreta. Por que temos um método de fábrica que cria objetos da classe Concrete?

Na ausência de Abstract Factory , o Cliente precisa conhecer detalhes de classes concretas. Esse acoplamento apertado foi removido com a Abstract Factory .

Agora o Método de Fábrica expõe um contrato que o cliente precisa usar. Você pode adicionar mais produtos à sua fábrica adicionando novos produtos, que implementam a interface exposta pelo Método de Fábrica.

Consulte estas perguntas relacionadas ao SE para melhor compreensão:

Qual é a diferença básica entre os padrões de fábrica e abstrato de fábrica?

Intenção:

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

Você pode entender Intenção, Estrutura, Inventário e Regras de ouro de Abstract Factory padrão a partir desta sourcemaking artigo.

Lista de controle:

  1. Decida se a independência da plataforma e os serviços de criação são a fonte atual de problemas.
  2. Mapeie uma matriz de plataformas versus produtos .
  3. Defina uma interface de fábrica que consiste em um método de fábrica por produto.
  4. Defina uma classe derivada de fábrica para cada plataforma que encapsule todas as referências ao novo operador.
  5. O cliente deve retirar todas as referências a new e usar os métodos de fábrica para criar os objetos do produto .

2

Resumo As fábricas são ótimas para oferecer suporte a várias plataformas, mantendo a base de código unificada. Suponha que você tenha um grande programa Qt ou GTK + ou .NET / Mono que deseja executar no Windows, Linux e OSX. Mas você tem um recurso implementado de maneira diferente em cada plataforma (talvez por meio da API do kernel32 ou de um recurso POSIX).

public abstract class Feature
{
    public abstract int PlatformSpecificValue { get; }

    public static Feature PlatformFeature
    {
        get
        {
            string platform;
            // do platform detection here
            if (platform == "Win32")
                return new Win32Feature();
            if (platform == "POSIX")
                return new POSIXFeature();
        }
    }

    // platform overrides omitted
}

Com este Abstract Factory, sua interface do usuário não precisa saber nada sobre a plataforma atual.

Feature feature = Feature.PlatformFeature;
Console.WriteLine(feature.PlatformSpecificValue);

1
Não entendi, como isso é diferente de usar métodos de fábrica para retornar um tipo abstrato para que o cliente não conheça os detalhes da implementação?
kiwicomb123

1

Se você observar os padrões de design, quase todos eles poderão ser redundantes. Mas qual padrão significa uma abordagem comumente usada para uma solução para um tipo semelhante de problemas. Um padrão de design fornece uma abordagem ou solução em nível de design para um conjunto de tipos semelhantes de problemas de design. O uso do padrão de design ajuda a resolver seu problema e, portanto, fornece mais rapidamente.



1

Acho o padrão Abstract Factory superestimado.

Primeiro de tudo, não é tão frequente que você tenha um conjunto de tipos inter-relacionados que deseja instanciar.

Em segundo lugar, o nível de indireção (abstração) fornecido pelas interfaces normalmente é suficiente quando se trabalha com injeção de dependência.

O exemplo típico de WindowsGui vs MacGui vs ... onde você teria um WindowsButton, MacButton, WindowsScrollBar, MacScrollbar, etc. geralmente é mais fácil de implementar definindo botões, barras de rolagem, etc. concretos , usando o padrão Visitor e / ou Interpreter para fornecer comportamento real.


existe um propósito específico para isso. com injeção de dependência, você não deseja localizadores de serviço mais distantes da raiz composta. em vez disso, você usa uma fábrica abstrata injetada.
Adam Tuliper - MSFT 26/10/10

2
bem ... usar o localizador de serviço com DI é um anti patteren. Uma fábrica abstrata é a solução universal quando precisamos criar DEPENDENCIES a partir dos valores de tempo de execução.
TheMentor

1

Eu acho que existe um lugar para o padrão abstrato de fábrica, em vez do simples padrão de fábrica, em locais onde suas instanciações são muito complicadas, muito complicadas e feias para uma única fábrica e muito complicadas para a interface do usuário compreender.

Digamos que essa é uma marca TYPE_A e não uma classe única. Digamos que exista uma família de 100 tipos de classes semelhantes do Tipo A e você precise instanciar um objeto a partir delas. Imagine que há informações detalhadas sofisticadas necessárias para transformar o objeto correto em uma marca de muitos tipos semelhantes de objetos, e nessa entidade de objeto você precisa saber exatamente quais parâmetros ajustar e como ajustá-los.

Na fábrica especial para esta marca, diferenciaremos e obteremos o objeto exato para instanciar e também como instanciar. saberemos que, de acordo com as informações da rede (digamos que cor está disponível na loja on-line) e de outros aplicativos e serviços em execução em segundo plano (parâmetros que a interface do usuário não os conhece).

E talvez amanhã tenhamos outra família, digamos type_B e type_C para instanciar. Portanto, a interface do usuário terá o "se mais" para saber se o usuário deseja um "tipo_A", "tipo_B" ou "tipo_C" - mas as classes de fábricas decidirão exatamente qual classe do tipo (da família) a ser construída e como ajustá-lo - quais valores definir para seus parâmetros ou enviar para o contratado. Tudo isso - de acordo com muitos parâmetros dos quais a interface do usuário não está ciente. Tudo isso será demais para uma única classe de fábrica.


0

Para responder diretamente à sua pergunta, você provavelmente pode fugir sem usar esse padrão de design.

No entanto, lembre-se de que a maioria dos projetos no mundo real evolui e você deseja fornecer algum tipo de extensibilidade para tornar seu projeto à prova de futuro.

De minha própria experiência, na maioria das vezes, uma fábrica é implementada e, à medida que o projeto cresce, ela é alterada para padrões de design mais complexos, como uma fábrica abstrata.


0

É tudo sobre dependências. Se você não se importa com acoplamentos e dependências rígidos, não precisa de uma fábrica abstrata. Mas isso será importante assim que você escrever um aplicativo que precise de manutenção.


0

Digamos que você crie um a.jar e alguém use seu jar e queira usar um novo objeto concreto no seu código. Se você não estiver usando o abstract factory, ela precisará modificar o seu código ou substituí-lo. Mas se você estiver usando a factory abstrata, ela poderá fornecer uma factory e passar para o seu código e está tudo bem.

Versão refinada: considere o seguinte cenário: outra pessoa escreveu uma estrutura. A estrutura usa uma fábrica abstrata e algumas fábricas concretas para criar muitos objetos em tempo de execução. Assim, você pode registrar facilmente sua própria fábrica na estrutura existente e criar seus próprios objetos. A estrutura está fechada para modificações e ainda é fácil de estender devido ao padrão abstrato de fábrica.


0

Esse padrão é particularmente útil quando o cliente não sabe exatamente que tipo criar. Como exemplo, digamos que um Showroom que vende exclusivamente telefones celulares obtenha uma consulta para os smartphones fabricados pela Samsung. Aqui não sabemos o tipo exato de objeto a ser criado (supondo que todas as informações de um telefone sejam agrupadas na forma de um objeto concreto). Mas sabemos que estamos procurando telefones inteligentes fabricados pela Samsung. Essas informações podem realmente ser utilizadas se nosso projeto tiver implementação abstrata de fábrica.

Compreendendo e implementando o padrão abstrato de fábrica em C #


0

O exemplo da vida real é fornecido no namespace System.Data.Common que possui classes básicas abstratas que incluem DbConnection, DbCommand e DbDataAdapter e são compartilhadas pelos provedores de dados do .NET Framework, como System.Data.SqlClient e System.Data.OracleClient, que permitir que um desenvolvedor escreva código genérico de acesso a dados que não dependa de um provedor de dados específico.

A classe DbProviderFactories fornece métodos estáticos para criar uma instância DbProviderFactory. A instância, em seguida, retorna um objeto de tipagem forte correto, com base nas informações do provedor e na cadeia de conexão fornecida no tempo de execução.

Exemplo:

 DataTable allProvidersTable = DbProviderFactories.GetFactoryClasses();

insira a descrição da imagem aqui

        /* Getting SqlClient family members */
        DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
        DbCommand dbCommand = dbProviderFactory.CreateCommand();
        DbConnection dbConnection = dbProviderFactory.CreateConnection();
        DbDataAdapter dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        SqlClientFactory sqlClientFactory = (SqlClientFactory)dbProviderFactory;
        SqlConnection sqlConnection = (SqlConnection)dbConnection;
        SqlCommand sqlCommand = (SqlCommand) dbCommand;
        SqlDataAdapter sqlDataAdapter = (SqlDataAdapter) dbDataAdapter;

        /* Getting OracleClient family members*/
        dbProviderFactory = DbProviderFactories.GetFactory("System.Data.OracleClient");
        dbCommand = dbProviderFactory.CreateCommand();
        dbConnection = dbProviderFactory.CreateConnection();
        dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        OracleClientFactory oracleClientFactory = (OracleClientFactory)dbProviderFactory;
        OracleConnection oracleConnection = (OracleConnection)dbConnection;
        OracleCommand oracleCommand = (OracleCommand)dbCommand;
        OracleDataAdapter oracleDataAdapter = (OracleDataAdapter)dbDataAdapter;

Exemplo-2 insira a descrição da imagem aqui

Arquitetura de solução de código insira a descrição da imagem aqui

As instâncias de fábrica de concreto são fornecidas usando o método estático de fábrica, conforme abaixo

public  class FurnitureProviderFactory
{
    public static IFurnitureFactory GetFactory(string furnitureType)
    {
        if (furnitureType == "Wood")
        {
            return new WoodenFurnitureFactory();
        }
        if (furnitureType == "Plastic")
        {
            return new PlasticFurnitureFactory();
        }
        throw new Exception("Undefined Furniture");
    }
}
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.