Pergunta

Alguém pode me explicar as vantagens de usar um contêiner do IOC sobre simplesmente codificar a implementação padrão em um construtor padrão?

Em outras palavras, o que há de errado nesse código?

public class MyClass
{
    private IMyInterface _myInterface;

    public MyClass()
    {
        _myInterface = new DefaultMyInterface();
    }

    public MyClass(IMyInterface myInterface)
    {
        _myInterface = myInterface;
    }
}

Até onde eu sei, essa classe suporta injeção de construtor o suficiente para que o teste e a zombaria da unidade sejam feitos facilmente. Além disso, o construtor padrão remove a sobrecarga computacional do contêiner do COI (para não mencionar todo o processo é muito mais transparente).

Os únicos benefícios que posso ver para usar um contêiner do IOC é se você precisar alternar a implementação de suas interfaces com frequência. Estou esquecendo de algo?

Foi útil?

Solução

A idéia do COI é delegar parte da funcionalidade do seu componente a outra parte do sistema. No mundo do COI, você tem componentes que não se conhecem. Seu exemplo viola isso, pois você está criando um acoplamento apertado entre o MyClass e alguma implementação do IMYInterface. A ideia principal Esse é o seu componente não tem conhecimento sobre como será usado. No seu exemplo, seu componente faz algumas suposições sobre seu uso.

Na verdade, essa abordagem pode funcionar, mas misturar o COI e a inicialização explícita de objetos não é uma boa prática IMO.

O COI fornece o acoplamento solto, realizando a ligação tardia pelo preço da clareza do código. Quando você adiciona um comportamento adicional a esse processo, ele torna as coisas ainda mais complicadas e pode levar a bugs quando alguns componentes podem potencialmente receber objeto com comportamento indesejado ou imprevisível.

Outras dicas

Escolher um lado :)

Em resumo, o COI é recomendado. O problema com o código é que não posso trocar a implementação padrão da dependência sem recompilar o código, como você declarou no final. O COI permite que você altere a configuração ou composição do seu objeto em um arquivo externo sem recompilação.
O COI assume a responsabilidade de "construção e montagem" do restante do código.O objetivo do COI não é tornar seu código testável ... é um efeito colateral agradável. (Assim como o código TDDED leva a um melhor design)

Não há nada de errado com este código e você ainda pode usá -lo com estruturas de injeção de dependência como Spring e Guice.

Muitos desenvolvedores vêem o arquivo de configuração XML da Spring como uma vantagem sobre as dependências da fiação no código, pois você pode alternar as implementações sem precisar de uma etapa de compilação. Esse benefício é realmente realizado em situações em que você já possui várias implementações compiladas no caminho da sua classe e deseja escolher a implementação no tempo de implantação. Você pode imaginar uma situação em que um componente é fornecido por terceiros após a implantação. Da mesma forma, pode haver um caso quando você deseja enviar implementações adicionais como patch após a implantação.

Mas nem todas as estruturas DI usam a configuração XML. Google Guice, por exemplo, tem módulos escritos como classes Java que devem ser compiladas como qualquer outra classe Java.

Então, qual é a vantagem de DI se você precisar de uma etapa de compilação? Isso nos leva de volta à sua pergunta original. Eu posso ver as seguintes vantagens:

  1. Abordagem padrão para DI durante a aplicação.
  2. Configuração perfeitamente separada de outra lógica.
  3. Capacidade de injetar proxies. A primavera, por exemplo
  4. Reutilização mais fácil da lógica de configuração. Quando você usa DI extensivamente, você verá uma árvore complexa de dependências evoluindo ao longo do tempo. Gerenciá -lo sem uma camada de configuração claramente separada e suporte à estrutura pode ser um pesadelo. O DI Frameworks facilita a reutilização da lógica de configuração por meio da herança e outros meios.

A única preocupação que tenho é (1) se a sua dependência de serviço padrão tiver outra dependência / de serviço secundário (e assim por diante ... seu DefaultMyInterface depende do ILogger) e (2) você precisa isolar a primeira dependência do serviço a partir do segundo ( Precisa testar o DefaultMyInterface com um ILogger de stub). Nesse caso, você evidentemente precisará perder o padrão "new DefaultMyInterface" e, em vez disso, fazer um de: (1) injeção de dependência pura ou (2) localizador de serviço ou (3) contêiner.buildup (new defaultMyInterface ());

Algumas das preocupações que outros pôsteres listados podem não ser justos com sua pergunta. Você não estava perguntando sobre várias implementações de "produção". Você está perguntando sobre teste de unidade. No caso de unidade, a sua abordagem, com minha primeira ressalva, parece legítima; Eu também consideraria usá -lo em casos simples de teste de unidade.

Da mesma forma, alguns respondedores expressaram preocupação com a repituição. Também não gosto de repitição, mas se (1) sua implementação padrão realmente for o seu padrão (Yagni: você não tem planos de alterar o padrão) e (2) você não acredita que a primeira ressalva que eu declarei se aplica e (3) Prefere a abordagem de código mais simples que você compartilhou, então não acho que essa forma específica de repitição seja um problema.

Além do acoplamento solto, um COI reduzirá a duplicação de código. Quando você usa um COI e deseja alterar a implementação padrão da sua interface, você deve alterá -lo em apenas um lugar. Quando você usa contutores padrão para injetar a implementação padrão, você deve alterá -lo em todos os lugares em que a interface é usada.

Além dos outros comentários, pode -se argumentar o princípio seco (não se repetir) nesses casos. É redudente ter que colocar esse código de construção padrão em todas as aulas. Também está introduzindo o manuseio especial de casos onde não precisa haver nenhum.

Não vejo por que sua técnica de codificar a implementação padrão não pôde ser usada junto com um contêiner do IOC. Apenas, as dependências que você não especificam na configuração levariam a implementação padrão.

Ou eu estou esquecendo de alguma coisa?

Um motivo pelo qual você pode querer usar um contêiner do COI seria facilitar a configuração tardia do seu software.

Digamos, por exemplo, você fornece várias implementações de uma interface específica - o cliente (ou sua equipe de serviços profissionais) pode decidir qual usar modificando o arquivo de configuração do IOC.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top