O único anti-padrão legítimo de injeção de dependência que eu conheço é o padrão Service Locator , que é um anti-padrão quando uma estrutura DI é usada para ele.
Todos os outros chamados anti-padrões DI que ouvi falar, aqui ou em outros lugares, são apenas casos ligeiramente mais específicos de anti-padrões gerais de design de OO / software. Por exemplo:
A injeção excessiva de construtor é uma violação do Princípio de Responsabilidade Única . Muitos argumentos construtores indicam muitas dependências; muitas dependências indica que a classe está tentando fazer muito. Geralmente, esse erro se correlaciona com outros odores de código, como nomes de classe incomumente longos ou ambíguos ("gerenciadores"). As ferramentas de análise estática podem detectar facilmente acoplamento aferente / eferente excessivo.
A injeção de dados, em oposição ao comportamento, é um subtipo do antipadrão poltergeist , com o 'geist nesse caso sendo o contêiner. Se uma classe precisa estar ciente da data e hora atuais, você não injeta a DateTime
, que são dados; em vez disso, você injeta uma abstração no relógio do sistema (eu costumo chamar o meu ISystemClock
, embora eu ache que exista um mais geral no projeto SystemWrappers ). Isso não está correto apenas para DI; é absolutamente essencial para a testabilidade, para que você possa testar funções que variam no tempo sem precisar realmente esperar por elas.
Declarar cada ciclo de vida como Singleton é, para mim, um exemplo perfeito de programação de cultos de carga e, em menor grau, o chamado " reservatório de objetos ", coloquialmente denominado . Já vi mais abusos contra os solteiros do que gostaria de lembrar, e muito pouco envolve DI.
Outro erro comum são os tipos de interface específicos da implementação (com nomes estranhos como IOracleRepository
) feitos apenas para poder registrá-lo no contêiner. Isso é, por si só, uma violação do Princípio da Inversão da Dependência (apenas porque é uma interface, não significa que seja realmente abstrato) e geralmente também inclui o inchaço da interface que viola o Princípio de Segregação da Interface .
O último erro que costumo ver é a "dependência opcional", que eles fizeram no NerdDinner . Em outras palavras, existe um construtor que aceita injeção de dependência, mas também outro construtor que usa uma implementação "padrão". Isso também viola o DIP e tende a levar a violações do LSP , pois os desenvolvedores, com o tempo, começam a fazer suposições sobre a implementação padrão e / ou iniciam novas instâncias usando o construtor padrão.
Como diz o velho ditado, você pode escrever FORTRAN em qualquer idioma . Injeção de dependência não é uma bala de prata que vai impedir que os desenvolvedores estragar o seu gerenciamento de dependência, mas faz prevenir uma série de erros comuns / anti-padrões:
...e assim por diante.
Obviamente, você não deseja projetar uma estrutura para depender de uma implementação específica de contêiner de IoC , como Unity ou AutoFac. Ou seja, mais uma vez, violando o DIP. Mas se você pensa em fazer algo assim, já deve ter cometido vários erros de design, porque a Injeção de Dependências é uma técnica de gerenciamento de dependências de uso geral e não está ligada ao conceito de um contêiner de IoC.
Qualquer coisa pode construir uma árvore de dependência; talvez seja um contêiner de IoC, talvez seja um teste de unidade com um monte de zombarias, talvez seja um driver de teste que fornece dados fictícios. Sua estrutura não deve se importar, e a maioria das estruturas que eu vi não se importa, mas elas ainda fazem uso pesado de injeção de dependência, para que possa ser facilmente integrada ao contêiner de IoC de sua escolha.
DI não é ciência de foguetes. Basta tentar evitar new
e static
exceto quando há uma razão convincente para usá-los, como um método de utilitário que não tem dependências externas, ou uma classe de utilitário que não poderia ter qualquer finalidade fora do quadro (interoperabilidade invólucros e chaves de dicionário são exemplos comuns de esta).
Muitos dos problemas com as estruturas de IoC surgem quando os desenvolvedores estão aprendendo a usá-los e, em vez de realmente mudar a maneira como lidam com dependências e abstrações para se ajustarem ao modelo de IoC, tente manipular o contêiner de IoC para atender às expectativas de seus clientes. estilo de codificação antigo, que geralmente envolvia alto acoplamento e baixa coesão. Código incorreto é código incorreto, independentemente de usar técnicas de DI ou não.