Pergunta

Tenho usado o StructureMap recentemente e gostei muito da experiência.No entanto, posso ver como alguém pode facilmente se deixar levar pela interface de tudo e acabar com classes que levam um monte de interfaces para seus construtores.Mesmo que isso realmente não seja um grande problema quando você está usando uma estrutura de injeção de dependência, ainda parece que existem certas propriedades que realmente não precisam ser interligadas apenas para fins de interface entre elas.

Onde você traça o limite sobre o que fazer a interface em vez de apenas adicionar uma propriedade à classe?

Foi útil?

Solução

Pense no seu design.DI permite que você altere o funcionamento do seu código por meio de alterações de configuração.Ele também permite quebrar dependências entre classes para que você possa isolar e testar objetos com mais facilidade.Você tem que determinar onde isso faz sentido e onde não.Não há resposta adequada.

Uma boa regra é que, se for muito difícil de testar, você terá alguns problemas com responsabilidade única e dependências estáticas.Isole o código que executa uma única função em uma classe e quebre essa dependência estática extraindo uma interface e usando uma estrutura de DI para injetar a instância correta em tempo de execução.Ao fazer isso, você torna trivial testar as duas partes separadamente.

Outras dicas

O principal problema com a injeção de dependência é que, embora dê a aparência de uma arquitetura fracamente acoplada, na verdade não dá.

O que você realmente está fazendo é mover esse acoplamento do tempo de compilação para o tempo de execução, mas ainda assim, se a classe A precisar de alguma interface B para funcionar, uma instância de uma classe que implemente a interface B ainda precisará ser fornecida.

A injeção de dependência só deve ser usada para as partes do aplicativo que precisam ser alteradas dinamicamente sem recompilar o código base.

Usos que considero úteis para um padrão de inversão de controle:

  • Uma arquitetura de plugin.Assim, ao definir os pontos de entrada corretos, você pode definir o contrato do serviço que deve ser prestado.
  • Arquitetura semelhante a um fluxo de trabalho.Onde você pode conectar vários componentes conectando dinamicamente a saída de um componente à entrada de outro.
  • Aplicativo por cliente.Digamos que você tenha vários clientes que pagam por um conjunto de “recursos” do seu projeto.Ao usar a injeção de dependência, você pode facilmente fornecer apenas os componentes principais e alguns componentes "adicionados" que fornecem apenas os recursos que o cliente pagou.
  • Tradução.Embora isso geralmente não seja feito para fins de tradução, você pode "injetar" arquivos de idiomas diferentes conforme necessário pelo aplicativo.Isso inclui interfaces de usuário RTL ou LTR conforme necessário.

A injeção de dependência deve ser usada apenas para as partes do aplicativo que precisam ser alteradas dinamicamente sem recompilar o código base

DI deve ser usado para isolar seu código de recursos externos (bancos de dados, webservices, arquivos xml, arquitetura de plugins).A quantidade de tempo necessária para testar sua lógica no código seria quase proibitiva em muitas empresas se você estivesse testando componentes que DEPENDEM de um banco de dados.

Na maioria dos aplicativos, o banco de dados não mudará dinamicamente (embora pudesse), mas de modo geral, é quase sempre uma boa prática NÃO vincular seu aplicativo a um recurso externo específico.A quantidade envolvida na mudança de recursos deve ser baixa (as classes de acesso a dados raramente devem ter uma complexidade ciclomática superior a uma em seus métodos).

O que você quer dizer com "apenas adicionando uma propriedade a uma classe?"

Minha regra prática é tornar a unidade de classe testável.Se sua classe depende dos detalhes de implementação de outra classe, isso precisa ser refatorado/abstraído até o ponto em que as classes possam ser testadas isoladamente.

EDITAR:Você menciona um monte de interfaces no construtor.Eu recomendaria usar setters/getters.Acho que isso torna as coisas muito mais fáceis de manter a longo prazo.

Faço isso apenas quando ajuda na separação de preocupações.

Como talvez em projetos cruzados, eu forneceria uma interface para implementadores em um de meus projetos de biblioteca e o projeto de implementação injetaria qualquer implementação específica que eles desejassem.

Mas é isso aí...todos os outros casos, apenas tornaria o sistema desnecessariamente complexo

Mesmo com todos os fatos e processos do mundo..toda decisão se resume a um julgamento - esqueci onde li isso
Acho que é mais uma questão de experiência/tempo de voo.Basicamente, se você vê a dependência como um objeto candidato que pode ser substituído em um futuro próximo, use injeção de dependência.Se eu vir 'classA e suas dependências' como um bloco para substituição, provavelmente não usarei DI para dependências de A.

O maior benefício é que isso ajudará você a entender ou até mesmo descobrir a arquitetura do seu aplicativo.Você poderá ver claramente como funcionam suas cadeias de dependências e fazer alterações em partes individuais sem exigir que você altere coisas não relacionadas.Você acabará com um aplicativo pouco acoplado.Isso o levará a um design melhor e você ficará surpreso quando puder continuar fazendo melhorias, porque seu design o ajudará a separar e organizar o código no futuro.Também pode facilitar o teste de unidade porque agora você tem uma maneira natural de substituir implementações de interfaces específicas.

Existem alguns aplicativos que são descartáveis, mas se houver alguma dúvida, eu iria em frente e criaria as interfaces.Depois de alguma prática, não é um grande fardo.

Outro item com o qual luto é onde devo usar injeção de dependência? Para onde você leva sua dependência do StructureMap?Somente no aplicativo de inicialização?Isso significa que todas as implementações devem ser transmitidas desde a camada superior até a camada inferior?

Eu uso Castle Windsor/Microkernel, não tenho experiência com mais nada mas gosto muito.

Quanto a como você decide o que injetar?Até agora, a seguinte regra prática me serviu bem:Se a classe for tão simples que não precisa de testes unitários, você pode ficar à vontade para instanciá-la na classe, caso contrário você provavelmente desejará ter uma dependência por meio do construtor.

Quanto a saber se você deve criar uma interface ou apenas tornar seus métodos e propriedades virtuais, acho que você deve seguir o caminho da interface se a) puder ver que a classe tem algum nível de reutilização em um aplicativo diferente (ou seja,um logger) ou b) se devido à quantidade de parâmetros do construtor ou porque há uma quantidade significativa de lógica no construtor, a classe será difícil de zombar.

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