O uso de DI / IoC deve remover todas as ocorrências da palavra-chave “nova”?


21

O uso de Injeção de Dependência e um contêiner de Inversão de Controle deve remover todas as ocorrências da newpalavra-chave " " do seu código?

Em outras palavras, todo objeto / dependência, não importa quão simples ou de curta duração, deve ser "registrado" no seu contêiner de IoC e injetado no método / classe que precisa usá-los?

Se não, onde você desenha a linha entre quais dependências / objetos são registrados no contêiner de IoC, versus o que é criado "in-line" como uma referência concreta, por meio da newpalavra - chave?


Eu tive o mesmo pensamento, na linha de "é 'novo' uma palavra de 4 letras?"
Michael Easter

Respostas:


27

Evite dogmas. Faça o que parece certo.

Eu prefiro usar "new" para estruturas de dados que não têm comportamento.

Se a classe tiver comportamento, examinarei o escopo desse comportamento. Se for apátrida e não tiver dependências, inclino-me para o "novo". Eu só começo a refatorar para o DI quando preciso adicionar uma dependência a recursos com estado (como um banco de dados ou um arquivo) ou a outras classes com esses recursos.


15
+1 para "evitar dogmas". É muito fácil cair na armadilha de seguir os movimentos sem entender o que está acontecendo ou onde deve ser usado corretamente.
Wayne Molina

@ Alex Eu gosto disso. Uma abordagem muito pragmática. Curiosamente, eu adicionaria algum código na minha pergunta, mostrando uma newdependência no meu próprio código que levou minha pergunta. Era uma classe simples, sem funcionalidade ou "comportamento", apenas propriedades simples.
CraigTP

11

No meu livro , forneço a distinção entre dependências estáveis ​​e voláteis . É mais importante usar o DI com dependências voláteis, mas muitas vezes você pode obter um acoplamento ainda mais flexível abstraindo e injetando dependências estáveis.

Lembre-se de que o aplicativo de DI não deve depender de um contêiner de DI . No caso em que o DI do Poor Man está em uso, nenhuma newpalavra-chave é removida - elas são movidas para a raiz da composição .

Algumas pessoas realmente preferem o DI do Pobre Homem ao invés de DI Containers. O custo de manutenção pode ser maior, mas você obtém segurança em tempo de compilação em troca. Como ouvi recentemente Dan North dizer: " newé o novo new" :)

O que isso significa é que, em vez de implementar a Raiz de Composição com um Contêiner de DI, ele conteria apenas um monte de newinstruções aninhadas .


Mark, para expandir um pouco o meu comentário no Twitter , os programadores são o lugar certo para perguntas conceituais e de quadro branco que não estão lidando com um erro específico em uma implementação.
Adam Lear

3
O Stack Overflow tem mais de 2000 perguntas na tag de injeção de dependência, e muitas delas são como esta. Programadores tem 23 perguntas na mesma tag. Com base nesses números, onde um desenvolvedor deve ter a maior chance de obter uma resposta para uma pergunta como essa?
precisa

1
Muitas dessas perguntas são anteriores aos programadores. Este site foi criado para retirar questões conceituais da SO e fornecer a elas um lar dedicado. E ainda estamos crescendo. É um trabalho em andamento, mas, idealmente, perguntas que não envolvem problemas específicos de implementação seriam migradas para cá. Enquanto isso, fazemos o que podemos.
Adam Lear

3

"new" não é uma palavra-chave proibida. Minhas regras pessoais:

Todos os "serviços" (eu chamo de serviço de classe projetada para fornecer um ou mais métodos relacionados a uma única coisa; por exemplo: acessar o banco de dados, recuperar / atualizar dados relacionados a um determinado domínio) são registrados no contêiner do IOC. Nenhuma classe deve ter que tomar uma decisão sobre como obter a implementação de um determinado serviço que ele precisa usar. Portanto, sempre que precisar usar um serviço existente, configure sua classe e o contêiner IOC para fornecê-lo. Imagine que você não está ciente de como sua implementação funciona; pode ser um serviço da Web, você não se importa.

Todos os beans ou modelos devem ser criados com a palavra-chave "new" ou com uma fábrica registrada no COI quando eu precisar que algumas propriedades padrão estejam ativadas. Há também o caso particular de classes de utilitário que contêm apenas métodos estáticos (por exemplo: um serviço de utilitário matemático). Se eles forem totalmente independentes e não precisarem de nenhuma conexão com o banco de dados ou outro serviço registrado no COI, deixo-os fora do COI e eles devem ser chamados estaticamente. No entanto, se uma dessas classes precisar usar um serviço registrado no IOC, eu a alterarei para uma classe singleton e a registrarei no IOC.


2

Gostaria apenas de acrescentar às respostas existentes criadas acima, newé perfeitamente adequado criar objetos que são objetos de valor puro (ou seja, possuem apenas propriedades / getters / setters). Consulte o Blog de testes do Google para obter mais detalhes.


+1 para o link. O ponto 9 dessa publicação no blog responde à pergunta e fornece uma distinção pragmática entre o que deve e o que não deve ser new'ed'
CraigTP

1

Claramente depende do idioma que você usa. Se o seu idioma obriga a usar objetos para representar objetos e registros reais (objeto de valor, estruturas), a resposta provavelmente não é.

Falando puramente de objetos "reais", não há nada errado em criar uma instância explicitamente. O que você deve ter em mente, porém, é que todas as classes devem seguir o princípio da responsabilidade única. Não deve ser responsabilidade de uma classe escolher o implementador de um serviço em que confia. No entanto, existem classes que têm essa mesma responsabilidade, ou seja, fornecer implementadores de determinados serviços. Um IoC pode ser dessa classe. De fato, qualquer tipo de fábrica é uma classe dessas.

Para resumir: Somente essas classes devem instanciar objetos diretamente, quem é responsável por escolher quais classes instanciar.
Você pode achar esses critérios úteis: http://en.wikipedia.org/wiki/GRASP_(object-oriented_design)#Creator


1

Uma palavra: Não.

Mais palavras: a injeção de dependência é exatamente isso. É um meio pelo qual você introduz recursos dos quais outro objeto depende, mas não deve conhecer os detalhes intricados de outra fonte. O uso do DI não significa que NADA no seu programa deve saber como criar qualquer outro objeto; de fato, afirmo que é altamente inviável para um programa não trivial evitar completamente a "nova" palavra-chave (ou alternativas baseadas em reflexão). No entanto, o DI significa que objetos que não devem ter que saber como criar objetos complexos que exigem muitas dependências que irão acoplar esse objeto ao outro, não devem ter todo esse conhecimento de acoplamento rígido.

Eu estudaria as duas principais teorias do design de software de O / O, GRASP e SOLID. O GRASP solicitará que você estude o objetivo do objeto e se pergunte: "Esse objeto deve ser responsável por criar novos objetos desse outro tipo? Isso faz parte da 'descrição do trabalho' desse objeto?" O SOLID vai um passo além: o "S" representa o "Princípio da responsabilidade única", que afirma inequivocamente que um objeto deve ter um trabalho e deve ser o único objeto no programa que executa esse trabalho específico.

Portanto, o GRASP geralmente o incentivaria a procurar nas classes existentes as quais criar esses novos objetos e encontrar uma cuja tarefa de criar esse objeto se encaixa com o que o objeto já faz, mantendo o nível desejado de "coesão". O SOLID lhe dirá que a coesão é fundamental; a tarefa de criar esses objetos deve ser dada a alguma fábrica que deve ser injetada em sua classe. Acho que você descobrirá, à medida que a complexidade do seu programa continua a crescer, que a adesão a qualquer uma dessas metodologias, com vontade de refatorar, resultará em arquiteturas muito semelhantes.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.