O mesmo problema básico que você costuma enfrentar com programação orientada a objetos, regras de estilo e praticamente tudo o mais. É possível - muito comum, de fato - fazer muita abstração e acrescentar muita indireção, e geralmente aplicar boas técnicas excessivamente e nos lugares errados.
Todo padrão ou outra construção que você aplica traz complexidade. A abstração e o indireto espalham informações, às vezes afastando detalhes irrelevantes, mas igualmente dificultando a compreensão do que está acontecendo. Toda regra que você aplica traz inflexibilidade, descartando opções que podem ser apenas a melhor abordagem.
O objetivo é escrever um código que faça o trabalho e seja robusto, legível e sustentável. Você é um desenvolvedor de software - não um construtor de torres de marfim.
Links relevantes
http://thedailywtf.com/Articles/The_Inner-Platform_Effect.aspx
http://www.joelonsoftware.com/articles/fog0000000018.html
Provavelmente, a forma mais simples de injeção de dependência (não ria) é um parâmetro. O código dependente depende dos dados e esses dados são injetados através da passagem do parâmetro.
Sim, é bobagem e não aborda o ponto de injeção de dependência orientado a objetos, mas um programador funcional lhe dirá que (se você tiver funções de primeira classe) esse é o único tipo de injeção de dependência que você precisa. O ponto aqui é pegar um exemplo trivial e mostrar os possíveis problemas.
Vamos pegar essa função tradicional simples - a sintaxe C ++ não é significativa aqui, mas eu tenho que escrevê-la de alguma forma ...
void Say_Hello_World ()
{
std::cout << "Hello World" << std::endl;
}
Eu tenho uma dependência que quero extrair e injetar - o texto "Hello World". Bastante fácil...
void Say_Something (const char *p_text)
{
std::cout << p_text << std::endl;
}
Como isso é mais inflexível que o original? Bem, e se eu decidir que a saída deve ser unicode. Eu provavelmente quero mudar de std :: cout para std :: wcout. Mas isso significa que minhas cordas precisam ser de wchar_t, não de char. Todo chamador deve ser alterado ou (mais razoavelmente), a implementação antiga é substituída por um adaptador que traduz a cadeia e chama a nova implementação.
Esse é o trabalho de manutenção que não seria necessário se mantivéssemos o original.
E se parecer trivial, dê uma olhada nesta função do mundo real a partir da API do Win32 ...
http://msdn.microsoft.com/en-us/library/ms632680%28v=vs.85%29.aspx
São 12 "dependências" para lidar. Por exemplo, se as resoluções de tela ficarem realmente grandes, talvez precisemos de valores de coordenadas de 64 bits - e outra versão do CreateWindowEx. E sim, já existe uma versão mais antiga, que provavelmente é mapeada para a versão mais recente nos bastidores ...
http://msdn.microsoft.com/en-us/library/ms632679%28v=vs.85%29.aspx
Essas "dependências" não são apenas um problema para o desenvolvedor original - todos que usam essa interface precisam procurar quais são as dependências, como são especificadas e o que elas significam e descobrir o que fazer para o aplicativo. É aqui que as palavras "padrões sensíveis" podem tornar a vida muito mais simples.
A injeção de dependência orientada a objetos não é diferente em princípio. Escrever uma classe é uma sobrecarga, tanto no texto do código-fonte quanto no tempo do desenvolvedor, e se essa classe for escrita para fornecer dependências de acordo com algumas especificações de objetos dependentes, o objeto dependente será bloqueado no suporte a essa interface, mesmo que seja necessário para substituir a implementação desse objeto.
Nada disso deve ser lido como alegando que a injeção de dependência é ruim - longe disso. Mas qualquer boa técnica pode ser aplicada excessivamente e no lugar errado. Assim como nem toda cadeia precisa ser extraída e transformada em parâmetro, nem todo comportamento de baixo nível precisa ser extraído de objetos de alto nível e transformado em uma dependência injetável.