Quando usar o DI e quando se criar em Java

8

Eu tenho uma quantidade decente de OOP com várias linguagens, mas sou bastante novo em Java.

Estou lendo vários tutoriais em que um grande número de objetos é criado no código de uma classe e estou tentando executá-los, mas construo versões das classes nos tutoriais que fazem Injeção de Dependências em vez de instanciar todos os classes próprias.

Mas o Java não é como as outras linguagens que eu usei, pois praticamente tudo é um objeto. Se eu fosse literalmente injetar tudo, o resultado seria muito confuso e difícil de seguir.

Obviamente, você não injetaria objetos String, e acho que existem outros objetos que você não injetaria, mas não tenho certeza de onde a linha deve ir. Em que momento a DI deixa de ser a coisa certa a fazer e quando começa a ser um fardo? Como você decide pragmaticamente o que injetar e o que apenas instanciar?

Para sua informação, os tutoriais que eu estou fazendo são http://edn.embarcadero.com/article/31995 e http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html para criar um cliente simples e servidor. Não estou copiando linha por linha, estou tentando criar classes equivalentes que seguem as melhores práticas

GordonM
fonte
1
Esta questão não é Java, mas as negociações sobre as formas de 'tudo injetar' em maneiras menos confuso: programmers.stackexchange.com/questions/190120/...
Jeffo

Respostas:

4

No .Net (que é semelhante nesse aspecto, tudo é um objeto), eu uso o DI principalmente com meus objetos de domínio (entidades, repositórios e serviços) e objetos de aplicativos (controladores, modelos de exibição), para que repositórios / serviços sejam injetados no controlador / veja modelos e similares. Isso significa que minha lógica de negócios e aplicativos é totalmente testável, que é o principal motivo pelo qual eu uso o DI.

Basicamente, os objetos nos quais você injeta e injeta coisas são principalmente objetos específicos da solução que você está construindo. Se algum objeto é "nativo" para o idioma ou estrutura (como .Net), provavelmente não há necessidade de injetá-lo. Muitos objetos precisam de uma string para representar dados, e uma string é basicamente um "recurso de idioma" que não é específico ao seu domínio. O mesmo se aplica a enumeráveis, listas, matrizes e muitas outras coisas que não precisam ser alteradas quando você deseja executar sua classe isoladamente do resto do sistema.

A coisa mais importante a se observar é o acoplamento entre as classes de domínio / aplicativo. Se um objeto não introduzir acoplamento rígido, geralmente é seguro apenas criá-lo. Uma das maneiras de verificar o acoplamento é tentar executar os métodos em uma classe isoladamente (que é basicamente o teste de unidade). O que precisa ser resolvido são todas as dependências que você precisa zombar, para garantir que a classe que você está testando esteja realmente executando isoladamente do sistema.

Ivan Pintar
fonte
Outra maneira de analisar é o que sua classe ou método está tentando fazer? O exemplo clássico é que você deseja salvar um objeto. A lógica nessa classe / método deve ser sobre como salvar o objeto, não sair e fazer o trabalho placa de caldeira de criar conexões etc, esse tipo de serviço / recurso poderia / deveria ser DI'd no.
Martijn Verburg
4

Em primeiro lugar, não há problema em usar a nova palavra-chave, realmente! A DI é uma técnica fantástica, mas há uma tentação de usá-la demais. Os horários em que você pode usar o DI são:

  • Dobros de teste - Geralmente, com testes de unidade, você deseja simular / testar o dobro de um recurso de terceiros, pois não deseja trazer esse recurso de terceiros (por exemplo, um banco de dados Oracle completo). Por exemplo, em vez de criar uma nova conexão de banco de dados com o grande banco de dados Oracle, convém substituir essa conexão por uma por um HSQL (no banco de dados de memória).

  • Quando você deseja controlar o escopo (~ vida útil) desse objeto e o ciclo de vida natural do objeto Java não funciona para você. Muitas estruturas de DI baseadas em Java permitem fazer isso.

  • Quando você quiser singletons.

  • Sempre que você precisar de uma Fábrica, Localizador de Serviço ou similar. Isso inclui se você precisar de fábricas diferentes (raras, mas isso acontece).

Em outros momentos, basta criar um novo objeto, na verdade, em caso de dúvida, criar um novo objeto - você sempre pode identificá-lo quando vir a necessidade mais tarde :-).

Martijn Verburg
fonte
Seu primeiro ponto PODE significar absolutamente qualquer coisa, então não tenho certeza de como você respondeu à pergunta. E já vi muitos lugares em que usar o DI para injetar uma fábrica, em vez de tentar construir uma fábrica via DI, é de longe a melhor solução, por isso também duvido do último ponto.
precisa
Editado para tornar os pontos um pouco mais claros
Martijn Verburg 11/03/13
Nunca ouvi a frase Test Doubles, pensei que você quisesse testar docs.oracle.com/javase/6/docs/api/java/lang/Double.html .
NimChimpsky 11/03/2019
1
@NimChimpsky um teste duplo é um termo genérico para qualquer simulação, esboço ou outro substituto. xunitpatterns.com/Test%20Double.html
0

Da Wikipedia :

O objetivo principal do padrão de injeção de dependência é permitir a seleção entre várias implementações de uma determinada interface de dependência em tempo de execução ou por meio de arquivos de configuração, em vez de em tempo de compilação. O padrão é particularmente útil para fornecer implementações de teste de stub de componentes complexos durante o teste, mas geralmente é usado para localizar componentes do plug-in ou para localizar e inicializar

Você não precisa injetar seqüências de caracteres, basta passá-las como parâmetros para o método relevante. Você não precisa injetar nenhum dado, além da configuração.

Bons testes de unidade ajudam a localizar erros e, portanto, você deve testar seu código independentemente de outras unidades de código. O DI pode ajudá-lo a conseguir isso.

Dave Hillier
fonte
0

Em geral, acho que uma classe só deveria ser newde outra classe.

Isso ocorre porque, quando você segue o caminho da injeção de dependência, todo objeto que está usando newprecisa injetar todas as dependências dos objetos que ele cria, o que significa que o objeto pai também precisa conhecer todas essas dependências. Se Ativer uma dependência Be Ccriar Ainstâncias new, Cprecisará automaticamente ter uma dependência B, mesmo que Cnunca use Bdiretamente. Primeiro, que viola a separação de preocupações, a menos que Co único trabalho seja criar As. Caso contrário, ele criará um problema se você desejar adicionar uma dependência, Aporque todas as coisas que a criam agora precisam adicionar a mesma dependência. Eles realmente não deveriam se preocupar com isso. É melhor terCdeclare uma dependência AFactorye AFactorytenha uma dependência B. Em seguida, você pode adicionar dependências a Atudo o que deseja e AFactoryprecisa mudar apenas.

Scott Whitlock
fonte
-1

"Em que momento a DI deixa de ser a coisa certa a fazer e quando começa a ser um fardo? ..."

Primeiro de tudo, eu gosto do DI e o uso muito, então não me interpretem mal

DI é ótimo para o lado do servidor, mas os jogos mudam todos juntos quando se trata de programação Gui. Por exemplo, eu incorporei o Guice a um aplicativo GUI existente desenvolvido no Swing

  • Você precisa refatorar bastante para se livrar de coisas como fábricas estáticas, dependências aninhadas, etc.
  • Você precisa estar ciente de como o contêiner de DI cria / manipula objetos, por exemplo, se ele cria objetos ansiosamente na inicialização, pode haver problemas de desempenho (pode ser qualquer aplicativo, mas particularmente nos aplicativos GUI, o atraso de 15 a 40 segundos é importante). Você pode alterar a configuração, desde que o contêiner DI permita.
  • Para incorporar o DI em um projeto existente, é necessário mais revolução do que evolução

Como lidar com dependências aninhadas?

digamos que você precise acessar algumas dependências em classes profundamente aninhadas, você pode usar o DI de uma das seguintes maneiras:

  • Modifique o construtor para ter injeção de construtor (Então, sabemos que o construtor está usando muitos parâmetros ...)?
  • Use injeção de campo (o que não é uma boa solução, porque estamos expondo nossos campos)
  • Use injeção de setter (saiba que precisamos criar setters desnecessários em nosso código)

Que tal se você deseja criar um objeto usando new () (porque o objeto precisa ser criado no Runtime, dependendo de alguns critérios) e deseja registrá-lo no contêiner (o Guice não lida com objetos criados com new (), que é bom )? Portanto, agora você precisa voltar o foco para o contêiner, em vez de desenvolver novas funcionalidades no aplicativo.

Palavras finais, em alguns casos, usando DesignPatterns + pensamento criativo e bom design de arquitetura, você pode evitar situações em que o gaine é pequeno e os aborrecimentos são altos como resultado da introdução do DI

sol4me
fonte