Injeção de Dependência vs Padrão de Fábrica


498

Na maioria dos exemplos citados para o uso de Injeção de Dependência, também podemos resolver usando o padrão de fábrica. Parece que quando se trata de uso / design, a diferença entre injeção de dependência e fábrica é embaçada ou fina.

Uma vez alguém me disse que é como você o usa que faz a diferença!

Uma vez eu usei o StructureMap um contêiner de DI para resolver um problema; posteriormente, o redesenhei para trabalhar com uma fábrica simples e removi as referências ao StructureMap.

Alguém pode me dizer qual é a diferença entre eles e onde usar o que, qual é a melhor prática aqui?


21
Não é possível que essas duas abordagens se complementem: usando injeção de dependência para injetar classes de fábrica?
Richard Ev

20
Seria muito bom se esta pergunta tivesse uma resposta com algum código! Ainda não vejo como o DI seria benéfico / diferente de usar uma fábrica para criação? Você só precisará substituir essa linha na classe factory para alterar qual obj / implementação é criada?
Gideon

2
A @gideon não o obrigaria a compilar seu aplicativo ou, pelo menos, o módulo que contém a classe factory?
ácido lisérgico

1
@liortal sim, isso mesmo. Fiz um longo estudo sobre DI desde esse comentário e agora entendo que o DI leva o método de fábrica um passo à frente.
Gideon

1
Confira esta ótima resposta: stackoverflow.com/questions/4985455/… - ele exprime muito bem e fornece exemplos de código.
Luis Perez

Respostas:


293

Ao usar uma fábrica, seu código ainda é realmente responsável pela criação de objetos. Por DI, você terceiriza essa responsabilidade para outra classe ou estrutura, que é separada do seu código.


172
O padrão de DI não requer nenhuma estrutura. Você pode fazer DI escrevendo manualmente fábricas que fazem DI. As estruturas de DI apenas facilitam.
Esko Luontola 17/02/09

28
@Perpetualcoder - Obrigado @Esko - Não se deixe envolver pela palavra framework, que significa alguma biblioteca avançada de terceiros.
21125 willcodejavaforfood

4
+1 @willcode obrigado! Então você precisa alterar os arquivos config / xml. Eu vejo. O link wiki en.wikipedia.org/wiki/… define o padrão de fábrica comoManually-Injected Dependency
gideon

5
Não tenho a vantagem de alterar 1 linha de XML versus alterar 1 linha de código. Você poderia elaborar?
Rafael Eyng 19/03/2015

1
Repita a resposta do OP, substituindo "DI" por "factory", ainda faz sentido.
Edson Medina

219

Eu sugeriria manter os conceitos claros e simples. A Injeção de Dependência é mais um padrão arquitetural para o acoplamento fraco de componentes de software. O padrão de fábrica é apenas uma maneira de separar a responsabilidade de criar objetos de outras classes para outra entidade. O padrão de fábrica pode ser chamado como uma ferramenta para implementar DI. A injeção de dependência pode ser implementada de várias maneiras, como DI usando construtores, mapeando arquivos xml etc.


4
É verdade que o Factory Pattern é uma das formas de implementar a injeção de dependência. Outro benefício do uso da Injeção de Dependência contra o Padrão de Fábrica é que o DI Frameworks lhe daria flexibilidade de como registrar suas abstrações nos tipos concretos. Como código como Config, XML ou configuração automática. Essa flexibilidade permitirá gerenciar a vida útil dos seus objetos ou decidir como e quando registrar suas interfaces.
Teoman shipahi

1
O padrão de fábrica oferece abstração de nível superior ao DI. Uma fábrica pode oferecer opções de configuração da mesma forma que o DI, mas também pode ocultar todos esses detalhes de configuração, para que a fábrica possa optar por mudar para uma implementação completamente diferente sem que o cliente saiba. O DI por si só não permite isso. O DI exige que o cliente especifique as alterações que ele deseja.
Neurônio

1
Boa resposta. Muitos estão confusos com essa pergunta: "Que pattens devo escolher?" De fato, os padrões de design são apenas uma maneira de resolver problemas em situações apropriadas. Se você não souber qual padrão de design você deve usar ou "Onde devo implementar o padrão?" então você não precisa disso no momento.
precisa saber é

2
Eu acho que é mais preciso dizer que o Factory Pattern é uma ferramenta para implementar a IoC (não a DI). Observe que o DI é uma forma de IoC
Hooman Bahreini

185

Injeção de dependência

Em vez de instanciar as peças em si, um carro pede as peças que ele precisa para funcionar.

class Car
{
    private Engine engine;
    private SteeringWheel wheel;
    private Tires tires;

    public Car(Engine engine, SteeringWheel wheel, Tires tires)
    {
        this.engine = engine;
        this.wheel = wheel;
        this.tires = tires;
    }
}

Fábrica

Une as peças para formar um objeto completo e oculta o tipo de concreto do chamador.

static class CarFactory
{
    public ICar BuildCar()
    {
        Engine engine = new Engine();
        SteeringWheel steeringWheel = new SteeringWheel();
        Tires tires = new Tires();
        ICar car = new RaceCar(engine, steeringWheel, tires);
        return car;
    }   
}

Resultado

Como você pode ver, Fábricas e DI se complementam.

static void Main()
{
     ICar car = CarFactory.BuildCar();
     // use car
}

Você se lembra de cachinhos dourados e dos três ursos? Bem, a injeção de dependência é assim. Aqui estão três maneiras de fazer a mesma coisa.

void RaceCar() // example #1
{
    ICar car = CarFactory.BuildCar();
    car.Race();
}

void RaceCar(ICarFactory carFactory) // example #2
{
    ICar car = carFactory.BuildCar();
    car.Race();
}

void RaceCar(ICar car) // example #3
{
    car.Race();
}

Exemplo # 1 - Esse é o pior porque oculta completamente a dependência. Se você olhasse o método como uma caixa preta, não teria idéia de que precisava de um carro.

Exemplo 2 - Isso é um pouco melhor, porque agora sabemos que precisamos de um carro, pois passamos em uma fábrica de carros. Mas desta vez estamos passando muito, já que todo o método realmente precisa é de um carro. Estamos passando em uma fábrica apenas para fabricar o carro quando o carro pode ser fabricado fora do método e passado.

Exemplo # 3 - Isso é ideal porque o método pede exatamente o que ele precisa. Nem muito nem pouco. Não preciso escrever um MockCarFactory apenas para criar o MockCars, posso passar o mock diretamente. É direto e a interface não mente.

Este Google Tech Talk, de Misko Hevery, é incrível e é a base do que eu deduzi meu exemplo. http://www.youtube.com/watch?v=XcT4yYu_TTs


1
O padrão de fábrica é injetado como DI.
Mangesh Pimpalkar

7
@ PhilGoetz O que você está descrevendo soa mais como o padrão do Localizador de Serviço. Eles têm objetivos semelhantes, no sentido de dissociar os serviços de seus consumidores. No entanto, existem muitas desvantagens no padrão do localizador de serviço. Principalmente, ocultar dependências não é uma coisa boa. O consumidor ainda precisa obter suas dependências, mas em vez de definir uma interface clara, elas são passadas 'secretamente' e dependem do estado global. No exemplo, o consumidor não tem idéia da fábrica, apenas pede o que precisa e não precisa se preocupar com a forma como essa necessidade é construída.
Despertar

1
@MatthewWhited A maioria das decisões de design tem um compromisso. Com o DI, você ganha flexibilidade, transparência e um sistema mais testável, mas com o custo de expor suas entranhas. Muitas pessoas acham isso uma troca aceitável. Isso não quer dizer que o DI seja sempre a melhor solução e essa questão não é sobre isso. O exemplo pretende mostrar a diferença entre DI e padrão de fábrica, mostrando alguns usos bons e ruins de cada um.
Despertar

3
Este não é um padrão de DI, é apenas uma implementação da IoC. O DI usa um ServiceLocator para determinar a dependência correta e injetá-la no construtor durante a criação do objeto. Seu código apenas segrega a criação de objetos do seu escopo de classe.
Diego Mendes

3
@DiegoMendes O que você está descrevendo é uma estrutura que automatiza o DI. O ServiceLocator, como você chama, faz o DI para você. O que estou mostrando é o próprio padrão, que não requer estruturas sofisticadas. Veja stackoverflow.com/a/140655/1160036 ou veja en.wikipedia.org/wiki/… : "[lista de estruturas] suporta injeção de dependência, mas não é necessário para fazer injeção de dependência". Além disso, "Uma injeção é a passagem de uma dependência para um objeto dependente". Você acabou complicando um conceito lindamente simples.
Despertar 02/02

50

A razão pela qual a Injeção de Dependência (DI) e os Padrões de Fábrica são semelhantes é porque são duas implementações do Inversion of Control (IoC), que é uma arquitetura de software. Simplificando, são duas soluções para o mesmo problema.

Portanto, para responder à pergunta, a principal diferença entre o padrão Factory e DI é como a referência do objeto é obtida. Com injeção de dependência, como o nome indica, a referência é injetada ou fornecida ao seu código. Com o padrão de fábrica, seu código deve solicitar a referência para que seu código busque o objeto. Ambas as implementações removem ou desacoplam a ligação entre o código e a classe ou o tipo subjacente da referência do objeto que está sendo usada pelo código.

Vale a pena notar que os padrões Factory (ou mesmo os padrões Abstract Factory que são fábricas que retornam novas fábricas que retornam referências a objetos) podem ser gravados para escolher dinamicamente ou vincular ao tipo ou classe de objeto solicitado em tempo de execução. Isso os torna muito semelhantes (ainda mais que o DI) ao padrão Service Locator, que é outra implementação da IoC.

O padrão de design da fábrica é bastante antigo (em termos de software) e existe há algum tempo. Desde a recente popularidade do padrão arquitetural IoC, ele está ressurgindo.

Eu acho que quando se trata de padrões de design de IoC: injetores injetam, localizadores localizam e as fábricas foram refatoradas.


3
Essa é a melhor resposta ... outras respostas não mencionam a IoC ou não reconhecem que a DI é uma forma de IoC.
Hooman Bahreini 29/10

Graças, quando eu estudei COI eu quase gritava que isso era apenas uma outra forma do padrão de fábrica, acontece que eles são realmente semelhantes entre si
Harvey Lin

40

Existem problemas que são fáceis de resolver com injeção de dependência que não são tão facilmente resolvidos com um conjunto de fábricas.

Algumas das diferenças entre, por um lado, inversão de controle e injeção de dependência (IOC / DI) e, por outro lado, um localizador de serviço ou um conjunto de fábricas (fábrica) são:

O IOC / DI é um ecossistema completo de objetos e serviços de domínio por si só. Ele define tudo para você da maneira que você especificar. Seus objetos e serviços de domínio são construídos pelo contêiner e não se constroem: portanto, eles não têm nenhuma dependência do contêiner ou de nenhuma fábrica. O IOC / DI permite um grau extremamente alto de configurabilidade, com toda a configuração em um único local (construção do contêiner) na camada superior da sua aplicação (a GUI, o front-end da Web).

O Factory abstrai uma parte da construção de seus objetos e serviços de domínio. Mas os objetos e serviços de domínio ainda são responsáveis ​​por descobrir como se construir e como obter todas as coisas das quais dependem. Todas essas dependências "ativas" são filtradas por todas as camadas do seu aplicativo. Não há um único lugar para configurar tudo.


26

Uma desvantagem do DI é que ele não pode inicializar objetos com lógica. Por exemplo, quando eu preciso criar um personagem com nome e idade aleatórios, o DI não é a escolha do padrão de fábrica. Com as fábricas, podemos facilmente encapsular o algoritmo aleatório da criação do objeto, que suporta um dos padrões de design chamados "Encapsular o que varia".


22

O gerenciamento do ciclo de vida é uma das responsabilidades que os recipientes de dependência assumem, além da instanciação e injeção. O fato de o contêiner às vezes manter uma referência aos componentes após a instanciação é o motivo pelo qual é chamado de "contêiner" e não de fábrica. Os contêineres de injeção de dependência geralmente mantêm apenas uma referência aos objetos para os quais ele precisa gerenciar os ciclos de vida ou que são reutilizados para futuras injeções, como singletons ou flyweights. Quando configurado para criar novas instâncias de alguns componentes para cada chamada ao contêiner, o contêiner geralmente esquece apenas o objeto criado.

De: http://tutorials.jenkov.com/dependency-injection/dependency-injection-containers.html


15

Acredito que o DI seja um tipo de camada de abstração nas fábricas, mas elas também fornecem benefícios além da abstração. Uma verdadeira fábrica sabe como instanciar um único tipo e configurá-lo. Uma boa camada de DI fornece a capacidade, através da configuração, de instanciar e configurar vários tipos.

Obviamente, para um projeto com alguns tipos simples que requer lógica de negócios relativamente estável em sua construção, o padrão de fábrica é simples de entender, implementar e funcionar bem.

OTOH, se você tiver um projeto que contém vários tipos cujas implementações você espera alterar com frequência, o DI oferece a flexibilidade através de sua configuração para fazer isso em tempo de execução sem precisar recompilar suas fábricas.


14

Teoria

Há dois pontos importantes a serem considerados:

  1. Quem cria objetos

    • [Fábrica]: você deve escrever COMO o objeto deve ser criado. Você tem uma classe Factory separada que contém lógica de criação.
    • [Injeção de Dependência]: Em casos práticos, são feitas por estruturas externas (por exemplo, em Java que seria spring / ejb / guice). A injeção acontece "magicamente" sem a criação explícita de novos objetos
  2. Que tipo de objetos ele gerencia:

    • [Fábrica]: geralmente responsável pela criação de objetos com estado
    • [Injections Dependency] Mais propensas a criar objetos sem estado

Exemplo prático de como usar injeção de fábrica e de dependência em um único projeto

  1. O que queremos construir

Módulo de aplicativo para criação de pedidos que contém várias entradas chamadas linha de pedidos.

  1. Arquitetura

Vamos assumir que queremos criar a seguinte arquitetura de camada:

insira a descrição da imagem aqui

Objetos de domínio podem ser objetos armazenados no banco de dados. Repositório (DAO) ajuda na recuperação de objetos do banco de dados. O serviço fornece API para outros módulos. Permite operações no ordermódulo

  1. Camada de domínio e uso de fábricas

As entidades que estarão no banco de dados são Order e OrderLine. O pedido pode ter vários OrderLines. Relação entre Order e OrderLine

Agora vem parte importante do design. Os módulos fora deste devem criar e gerenciar OrderLines por conta própria? Não. A linha do pedido deve existir apenas quando você tiver um pedido associado. Seria melhor se você pudesse ocultar a implementação interna para classes externas.

Mas como criar um pedido sem o conhecimento dos OrderLines?

Fábrica

Alguém que deseja criar um novo pedido usou o OrderFactory (que oculta detalhes sobre o fato de como criamos o pedido).

insira a descrição da imagem aqui

É assim que parecerá dentro do IDE. Classes fora do domainpacote serão usadas em OrderFactoryvez do construtor dentroOrder

  1. Injeção de Dependência A injeção de dependência é mais comumente usada com camadas sem estado, como repositório e serviço.

OrderRepository e OrderService são gerenciados pela estrutura de injeção de dependência. O repositório é responsável por gerenciar operações CRUD no banco de dados. O serviço injeta o Repositório e o utiliza para salvar / localizar as classes de domínio corretas.

insira a descrição da imagem aqui


Você pode esclarecer isso? [Factory]: Usually responsible for creation of stateful objects [Dependency Injections] More likely to create stateless objectsEu não entendo o porquê
Maksim Dmitriev

2
É provável que objetos com estado estejam na camada de aplicativo do domínio em que você mapeia seus dados para o banco de dados e geralmente não usa injeção de dependência. Fábrica é frequentemente utilizado para criar AggregateRoot da árvore de objetos complicados
Marcin Szymczak

12

Sei que essa pergunta é antiga, mas gostaria de adicionar meus cinco centavos,

Eu acho que a injeção de dependência (DI) é, de várias maneiras, como um padrão de fábrica (FP) configurável e, nesse sentido, qualquer coisa que você possa fazer com o DI poderá fazê-lo com essa fábrica.

Na verdade, se você usar o Spring, por exemplo, terá a opção de autowiring resources (DI) ou fazer algo assim:

MyBean mb = ctx.getBean("myBean");

E então use essa instância 'mb' para fazer qualquer coisa. Não é uma ligação para uma fábrica que retornará uma instância?

A única diferença real que noto entre a maioria dos exemplos de FP é que você pode configurar o que "myBean" é em um xml ou em outra classe, e uma estrutura funcionará como a fábrica, mas, além disso, é a mesma coisa, e você certamente pode ter um Factory que leia um arquivo de configuração ou obtenha a implementação conforme necessário.

E se você me pede a minha opinião (e eu sei que não), acredito que o DI faz a mesma coisa, mas apenas acrescenta mais complexidade ao desenvolvimento, por quê?

bem, por um lado, para você saber qual é a implementação que está sendo usada para qualquer bean que você usa automaticamente com DI, você precisa acessar a própria configuração.

mas ... e a promessa de que você não precisará conhecer a implementação do objeto que está usando? pfft! a sério? quando você usa uma abordagem como esta ... você não é o mesmo que escreve a implementação? e mesmo que não o faça, você não fica quase o tempo todo olhando como a implementação faz o que deveria fazer?

e, por último, não importa o quanto uma estrutura DI prometa que você construa coisas dissociadas dela, sem dependências de suas classes, se você estiver usando uma estrutura, construa tudo ao seu redor, se precisar mudar a abordagem ou a estrutura, não será uma tarefa fácil ... NUNCA! ... mas, como você constrói tudo em torno dessa estrutura específica, em vez de se preocupar com qual é a melhor solução para o seu negócio, você enfrentará um grande problema ao fazer isso.

De fato, o único aplicativo de negócios real para uma abordagem FP ou DI que eu posso ver é se você precisar alterar as implementações usadas no tempo de execução , mas pelo menos as estruturas que conheço não permitem que você faça isso, você deve sair tudo perfeito na configuração no momento do desenvolvimento e, se você precisar, use outra abordagem.

Portanto, se eu tiver uma classe que tenha desempenho diferente em dois escopos no mesmo aplicativo (digamos, duas empresas de uma holding), tenho que configurar a estrutura para criar dois beans diferentes e adaptar meu código para usar cada um. Não é o mesmo que escrever apenas algo assim:

MyBean mb = MyBeanForEntreprise1(); //In the classes of the first enterprise
MyBean mb = MyBeanForEntreprise2(); //In the classes of the second enterprise

o mesmo que este:

@Autowired MyBean mbForEnterprise1; //In the classes of the first enterprise
@Autowired MyBean mbForEnterprise2; //In the classes of the second enterprise

E isto:

MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise1"); //In the classes of the first enterprise
MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise2"); //In the classes of the second enterprise

De qualquer forma, você terá que alterar algo em seu aplicativo, sejam classes ou arquivos de configuração, mas precisará realizá-lo e reimplementá-lo.

Não seria bom fazer algo assim:

MyBean mb = (MyBean)MyFactory.get("mb"); 

Dessa forma, você define o código da fábrica para obter a implementação correta em tempo de execução, dependendo da empresa do usuário registrado? Agora isso seria útil. Você pode simplesmente adicionar um novo jar com as novas classes e definir as regras, talvez também em tempo de execução (ou adicionar um novo arquivo de configuração, se você deixar esta opção em aberto), sem alterações nas classes existentes. Esta seria uma fábrica dinâmica!

isso não seria mais útil do que ter que escrever duas configurações para cada empresa e talvez até ter dois aplicativos diferentes para cada uma?

Você pode me dizer que eu não preciso fazer a alternância no tempo de execução, portanto, eu configuro o aplicativo e, se eu herdar a classe ou usar outra implementação, basta alterar a configuração e reimplementar. Ok, isso também pode ser feito com uma fábrica. E seja honesto, quantas vezes você faz isso? talvez apenas quando você tiver um aplicativo que será usado em outro lugar da sua empresa e você passará o código para outra equipe, e eles farão coisas assim. Mas ei, isso também pode ser feito com a fábrica e seria ainda melhor com uma fábrica dinâmica !!

De qualquer forma, a seção de comentários está aberta para você me matar.


3
Muitos desenvolvedores pensam que as estruturas de injeção de dependência são criadas para trazer algo novo. Como você bem explica, as fábricas tradicionais (geralmente a fábrica abstrata) podem desempenhar o mesmo papel de inversão de dependência. Inversão vs Injeção? Para mim, o único "benefício" da estrutura de Injeção de Dependências é que não precisamos alterar / recompilar o código (já que geralmente é configurável com XML como o Spring) quando uma dependência é adicionada / alterada. Por que evitar recompilar? A fim de evitar possíveis erros humanos ao alterar a dependência / fábrica. Mas, com nossos excelentes IDEs, a refatoração funciona bem :)
Mik378

6

O COI é um conceito implementado de duas maneiras. Criação de dependência e injeção de dependência, Fábrica / Resumo de fábrica são o exemplo da criação de dependência. A injeção de dependência é construtora, configuradora e interface. O núcleo do COI é não depender das classes concretas, mas definir o resumo dos métodos (por exemplo, uma interface / classe abstrata) e usar esse resumo para chamar o método da classe concreta. Como padrão de fábrica, retorne a classe base ou interface. Injeção de dependência semelhante usa classe / interface base para definir valor para objetos.


4

Com a injeção de dependência, o cliente não precisa obter suas dependências por conta própria, tudo preparado com antecedência.

Com as fábricas, alguém precisa chamá-las para levar os objetos gerados para o local onde são necessários.

A diferença está principalmente nessa linha onde é feita a chamada da fábrica e a busca do objeto construído.

Mas com as fábricas, você deve escrever essa linha 1 em todos os lugares que precisar desse objeto. Com o DI, você só precisa criar a fiação (relação entre uso e objeto criado) uma vez e confiar na presença do objeto posteriormente em qualquer lugar. Por outro lado, o DI frequentemente requer um pouco mais de trabalho (quanto depende da estrutura) do lado da preparação.


3

Eu tive a mesma pergunta assim que li sobre DI e acabei neste post. Então, finalmente, é isso que eu entendi, mas, por favor, me corrija se estiver errado.

"Há muito tempo, havia pequenos reinos com seus próprios órgãos de governo controlando e tomando decisões com base em suas próprias regras escritas. Mais tarde, formou um grande governo eliminando todos esses pequenos órgãos de governo que têm um conjunto de regras (constituição) e são implementados pelos tribunais"

Os órgãos de governo dos pequenos reinos são "Fábricas"

O grande governo é o "Injetor de Dependências".


1
Então, QUANDO um codsider um governo pequeno anterior agora é grande? Por que medida?
Prisioneiro ZERO

3

Você pode dar uma olhada neste link para comparar as duas abordagens (e outras) em um exemplo real.

Basicamente, quando os requisitos mudam, você acaba modificando mais código se usar fábricas em vez de DI.

Isso também é válido com o DI manual (ou seja, quando não há uma estrutura externa que forneça as dependências para seus objetos, mas você as transmite em cada construtor).


3

A maioria das respostas aqui explica a diferença conceitual e os detalhes de implementação de ambos. No entanto, não consegui encontrar explicações sobre a diferença na aplicação sobre a qual a IMO é a mais importante e o OP perguntou. Então, deixe-me reabrir este tópico ...

Uma vez alguém me disse que é como você o usa que faz a diferença!

Exatamente. Em 90% dos casos, você pode obter referência de objeto usando Factory ou DI e, geralmente, acaba com o último. Em outros 10% dos casos, usar o Factory é a maneira correta . Esses casos incluem a obtenção de objetos por variável nos parâmetros de tempo de execução. Como isso:

IWebClient client = factoryWithCache.GetWebClient(url: "stackoverflow.com",
        useCookies: false, connectionTimeout: 120);

Nesse caso, clientnão é possível obter DI (ou pelo menos requer uma solução alternativa feia). Portanto, como regra geral para tomar uma decisão: se uma dependência puder ser obtida sem nenhum parâmetro calculado em tempo de execução, o DI será preferido, caso contrário, use Factory.


2

Eu acredito que o DI é uma maneira de configurações ou instanciar um bean. O DI pode ser feito de várias maneiras, como construtor, setter-getter etc.

O padrão de fábrica é apenas outra maneira de instanciar beans. esse padrão será usado principalmente quando você precisar criar objetos usando o padrão de design de fábrica, porque, ao usar esse padrão, você não configura as propriedades de um bean, apenas instancia o objeto.

Verifique este link: Injeção de Dependência


2

Binoj,

Eu não acho que você precise escolher um sobre o outro.

O ato de mover uma classe ou interface dependente para um construtor ou setter de classe segue o padrão DI. O objeto que você passa para o construtor ou conjunto pode ser implementado com o Factory.

Quando usar? Use o padrão ou padrões que estão na sua casa do leme do desenvolvedor. Com o que eles se sentem mais confortáveis ​​e mais fáceis de entender.


2

Acredito que três aspectos importantes governam os objetos e seu uso:
1. Instanciação (de uma classe juntamente com a inicialização, se houver).
2. Injeção (da instância criada) onde for necessária.
3. Gerenciamento do ciclo de vida (da instância criada).

Usando o padrão de fábrica, o primeiro aspecto (instanciação) é alcançado, mas os dois restantes são questionáveis. A classe que usa outras instâncias deve codificar as fábricas (em vez de as instâncias serem criadas), o que dificulta a capacidade de acoplamento solto. Além disso, gerenciamento do ciclo de vidade instâncias torna-se um desafio em um aplicativo grande em que uma fábrica é usada em vários locais (principalmente, se a fábrica não gerencia o ciclo de vida da instância que retorna, fica feia).

Por outro lado, usando um DI (do padrão IoC), todos os 3 são abstraídos fora do código (para o contêiner DI) e o bean gerenciado não precisa de nada sobre essa complexidade. Acoplamento solto , um objetivo arquitetônico muito importante pode ser alcançado silenciosamente confortavelmente. Outro objetivo arquitetural importante, a separação de preocupações pode ser alcançada muito melhor do que as fábricas.

Enquanto as fábricas podem ser adequadas para pequenas aplicações, as maiores seriam melhores para escolher o DI do que as fábricas.


1

Meus pensamentos:

Injeção de Dependência: passe colaboradores como parâmetros para os construtores. Estrutura de injeção de dependência: uma fábrica genérica e configurável para criar os objetos a serem passados ​​como parâmetros para os construtores.


1
Sim, exatamente. Quase todas as menções de Injeção de Dependência (DI) nestas Perguntas e Respostas usam mal o termo em contraste com esta definição. Um DIC (Dependency Injection Container) é a estrutura mais comum que atua como uma fábrica genérica e configurável para criar objetos.
CXJ

1

Uma estrutura de injeção é uma implementação do padrão de fábrica.

Tudo depende de suas necessidades. Se você precisar implementar o padrão de fábrica em um aplicativo, é muito provável que seus requisitos sejam atendidos por uma das inúmeras implementações de estruturas de injeção existentes.

Você só deve implementar sua própria solução se seus requisitos não puderem ser atendidos por nenhuma das estruturas de terceiros. Quanto mais código você escreve, mais você precisa manter. Código é um passivo, não um ativo.

Os argumentos sobre qual implementação você deve usar não são tão importantes quanto entender as necessidades de arquitetura do seu aplicativo.


1

Padrão de Design de Fábrica

O padrão de design da fábrica é caracterizado por

  • Uma interface
  • Classes de implementação
  • Uma fábrica

Você pode observar algumas coisas quando se pergunta como abaixo

  • Quando a fábrica criará objeto para as classes de implementação - tempo de execução ou tempo de compilação?
  • E se você quiser mudar a implementação em tempo de execução? - não é possível

Estes são tratados por injeção de dependência.

Injeção de dependência

Você pode ter maneiras diferentes de injetar dependência. Para simplificar, vamos com a injeção de interface

No DI, o contêiner cria as instâncias necessárias e as "injeta" no objeto.

Assim, elimina a instanciação estática.

Exemplo:

public class MyClass{

  MyInterface find= null;

  //Constructor- During the object instantiation

  public MyClass(MyInterface myInterface ) {

       find = myInterface ;
  }

  public void myMethod(){

       find.doSomething();

  }
}

1

De um valor nominal, eles parecem iguais

Em termos muito simples, o Padrão de Fábrica, um Padrão de Criação ajuda a criar um objeto para nós - "Definir uma interface para criar um objeto". Se tivermos um tipo de pool de objetos com valor-chave (por exemplo, Dicionário), passando a chave para a Factory (refiro-me ao Simple Factory Pattern), você poderá resolver o Type. Tarefa concluída! O Framework de Injeção de Dependência (como Mapa de Estrutura, Ninject, Unity ... etc), por outro lado, parece estar fazendo a mesma coisa.

Mas ... "Não reinvente a roda"

Do ponto de vista arquitetônico, é uma camada vinculativa e "Não reinvente a roda".

Para um aplicativo de nível corporativo, o conceito de DI é mais uma camada arquitetural que define dependências. Para simplificar ainda mais, você pode pensar nisso como um projeto separado da biblioteca de classes, que resolve a dependência. A principal aplicação depende deste projeto, em que o resolvedor de dependências se refere a outras implementações concretas e à resolução de dependências.

Além de "GetType / Create" de uma fábrica, na maioria das vezes precisamos de mais recursos (capacidade de usar XML para definir dependências, zombaria e testes de unidade etc.). Desde que você se referiu ao Mapa da Estrutura, consulte a lista de recursos do Mapa da Estrutura . É claramente mais do que simplesmente resolver um mapeamento simples de objetos. Não reinvente a roda!

Se tudo que você tem é um martelo, tudo parece um prego

Dependendo dos seus requisitos e do tipo de aplicativo que você cria, você precisa fazer uma escolha. Se tiver apenas alguns projetos (pode ser um ou dois ..) e envolver poucas dependências, você poderá escolher uma abordagem mais simples. É como usar o acesso a dados do ADO .Net sobre o Entity Framework para chamadas simples de um ou dois bancos de dados, onde a introdução do EF é um exagero nesse cenário.

Mas, para um projeto maior ou se seu projeto aumentar, eu recomendo que você tenha uma camada de DI com uma estrutura e dê espaço para alterar a estrutura de DI que você usa (use uma fachada no aplicativo principal (Web App, Web API, desktop ..etc.).


1

Com uma fábrica, você pode agrupar interfaces relacionadas. Portanto, se os parâmetros passados ​​podem ser agrupados em uma fábrica, também é uma boa solução para constructor overinjectionexaminar este código *):

public AddressModelFactory(IAddressAttributeService addressAttributeService,
        IAddressAttributeParser addressAttributeParser,
        ILocalizationService localizationService,
        IStateProvinceService stateProvinceService,
        IAddressAttributeFormatter addressAttributeFormatter)
    {
        this._addressAttributeService = addressAttributeService;
        this._addressAttributeParser = addressAttributeParser;
        this._localizationService = localizationService;
        this._stateProvinceService = stateProvinceService;
        this._addressAttributeFormatter = addressAttributeFormatter;
    }

Olhe para o construtor, você só precisa passar o IAddressModelFactorylá, menos parâmetros *):

 public CustomerController(IAddressModelFactory addressModelFactory,
        ICustomerModelFactory customerModelFactory,
        IAuthenticationService authenticationService,
        DateTimeSettings dateTimeSettings,
        TaxSettings taxSettings,
        ILocalizationService localizationService,
        IWorkContext workContext,
        IStoreContext storeContext,
        ICustomerService customerService,
        ICustomerAttributeParser customerAttributeParser,
        ICustomerAttributeService customerAttributeService,
        IGenericAttributeService genericAttributeService,
        ICustomerRegistrationService customerRegistrationService,
        ITaxService taxService,
        CustomerSettings customerSettings,
        AddressSettings addressSettings,...

Você vê em CustomerControllermuitos parâmetros passados. Sim, você pode ver isso, constructor overinjectionmas é assim que o DI funciona. E não há nada errado com oCustomerController .

*) O código é do nopCommerce.


1

Em termos simples, o método Injeção de Dependência vs Fábrica implica um mecanismo de push versus pull, respectivamente.

Mecanismo de tração : a classe indiretamente depende do método Factory, que por sua vez depende das classes concretas.

Mecanismo de pressão : O componente raiz pode ser configurado com todos os componentes dependentes em um único local, promovendo assim alta manutenção e acoplamento solto.

Com o método Factory, a responsabilidade ainda recai sobre a classe (embora indiretamente) para criar um novo objeto, onde, como na injeção de dependência, essa responsabilidade é terceirizada (ao custo de vazar a abstração)


0

Eu acho que estas são ortogonais e podem ser usadas juntas. Deixe-me mostrar um exemplo que me deparei recentemente no trabalho:

Estávamos usando a estrutura Spring em Java para DI. Uma classe singleton ( Parent) teve que instanciar novos objetos de outra classe ( Child), e esses tinham colaboradores complexos:

@Component
class Parent {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    void method(int p) {
        Child c = new Child(dep1, dep2, ..., depN, p);
        // ...
    }
}

Neste exemplo, Parentprecisa receber DepXinstâncias apenas para passá-las ao Childconstrutor. Problemas com isso:

  1. Parenttem mais conhecimento do Childque deveria
  2. Parent tem mais colaboradores do que deveria
  3. A adição de dependências Childenvolve a alteraçãoParent

Foi quando percebi que um Factoryse encaixaria aqui perfeitamente:

  1. Oculta todos os parâmetros, exceto os verdadeiros da Childclasse, como visto porParent
  2. Ele encapsula o conhecimento da criação de um Child, que pode ser centralizado na configuração do DI.

Esta é a Parentclasse simplificada e a ChildFactoryclasse:

@Component
class Parent {
    // ...
    @Autowired
    Parent(ChildFactory childFactory) {
        this.childFactory = childFactory;
    }

    void method(int p) {
        Child c = childFactory.newChild(p);
        // ...
    }
}

@Component
class ChildFactory {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
        // ...
        this.depN = depN;
    }

    Child newChild(int p) {
        return new Child(dep1, dep2, ..., depN, p);
    }
}

0

Você usa injeção de dependência quando sabe exatamente que tipo de objetos você precisa neste momento. Enquanto no caso do padrão de fábrica, você apenas delega o processo de criação de objetos para a fábrica, pois não sabe ao certo o tipo exato de objetos que precisa.


-1

Uso os dois para criar uma estratégia de Inversão de controle com mais legibilidade para desenvolvedores que precisam mantê-la depois de mim.

Eu uso um Factory para criar meus diferentes objetos de Camada (Negócios, Acesso a Dados).

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

Outro desenvolvedor verá isso e, ao criar um objeto Business Layer, ele procura no BusinessFactory e Intellisense fornece ao desenvolvedor todas as camadas de negócios possíveis para criar. Não precisa jogar, encontre a interface que eu quero criar.

Essa estrutura já é Inversão de controle. Não sou mais responsável por criar o objeto específico. Mas você ainda precisa garantir a injeção de dependência para poder mudar as coisas facilmente. Criar sua própria injeção de dependência personalizada é ridículo, então eu uso o Unity. Dentro do CreateCarBusiness (), peço ao Unity que resolva qual classe pertence a isso e sua vida útil.

Portanto, minha estrutura de injeção de dependência de fábrica de código é:

public static class BusinessFactory
{
    public static ICarBusiness CreateCarBusiness()
    {
       return Container.Resolve<ICarBusiness>();
    }
}

Agora eu tenho o benefício de ambos. Meu código também é mais legível para outros desenvolvedores quanto aos escopos dos meus objetos que eu uso, em vez da Injeção de Dependência do Construtor, que diz apenas que todo objeto está disponível quando a classe é criada.

Eu uso isso para alterar meu acesso a dados do banco de dados para uma camada de acesso a dados codificada personalizada ao criar testes de unidade. Não quero que meus testes de unidade se comuniquem com bancos de dados, servidores da web, servidores de e-mail etc. Eles precisam testar minha camada de negócios porque é aí que está a inteligência.


-4

Usar injeção de dependência é muito melhor na minha opinião, se você estiver: 1. implantando seu código em uma pequena partição, porque ele lida bem com a dissociação de um código grande. 2. testability é um dos casos em que o DI pode ser usado porque você pode simular facilmente os objetos não dissociados. com o uso de interfaces, você pode facilmente zombar e testar cada objeto. 3. você pode revisar simultaneamente cada parte do programa sem precisar codificar a outra parte, uma vez que esta é desacoplada.

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.