Dúvidas quanto ao Dependency Injection

Desenvolvendo uma aplicação costumava criar uma interface para cada repositório e uma implementação correspondente para cada tipo de persitência, nos controladores de cada entidade tinha um atributo do tipo da interface de repositório e costumava fazer dos meus controladores singletons , nos quais em seus construtores instanciaria a classe q implementa o tipo de repositorio. Um colega meu falou sobre uma padrão chamado Dependency Injection, q livra o controlador de instanciar diretamente a classe concreta q implementa a interface do repositório. Achei um artigo no javafree.org (http://www.javafree.org/content/view.jf?idContent=1), bem generoso, q fala sobre tal padrão. Em linhas gerais eu entendi o funcionamento, mas tenhos duas perguntas:

1: O padrão dependency injection depende dos tais containers dos quais o Martin Fowler citou?? (Spring, picocontainer, etc)???

2: Consegui entender q ao utilizar o tal padrão eu realmente me livro de instanciar a classe concreta no controlador, porém tenho toda uma parafernália adicional, e definitivamente em algum momento terei q definir qual classe concreta desejo instanciar. Será q vale tanta complexidade??

Eu sou iniciante no mundo dos design patterns, me perdoem se estou falando besteira, mas eh q essas questões a mim n ficaram claras.

Segue um código simples de como costumo estruturar meus sistemas, supondo repositórios e controladores referentes a uma entidade arbitrária, Pessoa:

public interface IRepositorioPessoa {

	//Métodos do repositório
	
}
public class RepositorioPessoaMySQL implements IRepositorioPessoa{

	private static RepositorioPessoaMySQL instance = null;
	
	private RepositorioPessoaMySQL(){}
	
	public static RepositorioPessoaMySQL getInstance(){
		if (instance == null){
			instance = new RepositorioPessoaMySQL();
		}
		
		return instance;
	}
	
	//Métodos concretos definidaos pela interface
	
}

public class ControladorPessoa {

	private IRepositorioPessoa repositorio;
	
	private static ControladorPessoa instance;
	
	private ControladorPessoa(){
		repositorio = RepositorioPessoaMySQL.getInstance();
	}
	
	public static ControladorPessoa getInstance(){
		if (instance == null){
			instance = new ControladorPessoa();
		}
		
		return instance;
	}
	
	//Métodos do controlador
	
}

Se possível comentem sobre o q vcs acham da minha abordagem (se existem melhores forams de estruturar) e caso o Dependency Injection fosse agregar valor à implementação, implementaria o tal padrão? Teria q usar os Containers leves??

Antecipadamente obrigado a todos.

Sim e não. O padrão em si não depende desses containeres. Mas de alguma forma, alguém tem de injetar as dependências (sim, tecnicamente seria também um container). Você pode fazer isso na mão (e boa sorte, pois você vai precisar dela) ou usar um (apenas um já basta) container dentre esses citados e deixar que ele resolva a complexidade para você.

Se você usar um container desses, quase toda a parafernália já foi feita. Você (quase) só precisará configurá-lo.

Quanto ao teu código, você tem dois singletons hard-coded. Se você usar o Spring como container (não sei quanto aos outros), os objetos injetados serão singletons “por default” e você não precisará mais implementar essa coisa de getInstance. E se quiser que determinada injeção deixe de usar singletons, basta alterar o teu arquivo de configuração (sem mexer em nenhum pentelhinho da classe).

Ah… IRepositorioPessoa fica melhor como RepositorioPessoa… :wink:

Para usar IoC e DI vc precisa de um framework ou container que forneçam essa funcionalidade. É claro que vc tb pode na mão implementar o seu próprio container de IoC e DI, mas normalmente um bom framework web, Spring, etc já vão te fornecer isso.

IoC = controle de criação de instancias sem usar NEW de forma que as suas instancias virem componentes e sejam criadas e gerenciadas através de um único lugar, normalmente junto com as demais configurações da sua aplicação. IoC pode possuir escopos, entre eles: Application (espécie de singleton), Session e Request.

DI = auto-wiring, ou interligação de vários componentes, ou seja, um componente A depende de um objeto/componente B, então o DI vai pegar o B e injetar dentro do A pra vc de forma automática. O DI, diferentemente do IoC, não instancia nada, apenas faz a ligação automática (auto-wiring).

IoC = implementação
DI = interfaces

Dá uma lida aqui que pode te ajudar:

IoC = http://forum.mentaframework.org/posts/list/477.page

DI = http://forum.mentaframework.org/posts/list/481.page

Entendo que IoC é mais abrangente do que isso.

Onde o DI vai pegar o B?
Por que ele não instancia nada?
Você poderia me passar referências que embasem essas afirmações fora do escopo do Mentawai?

No meu entendimento, e acho que do Fowler também, DI é uma forma dentre as diversas de ter IoC.

Eu simplifiquei a explicação e vc citou um artigo bastante extenso. Se possível cite alguma coisa de IoC que a minha descrição não contemplou, para que eu e os outros que estão acompanhando esse post possam tirar algum proveito prático.

DI geralmente é para ser usado com IoC, ou seja, o IoC vai entregar o B para o DI fazer o auto-wiring.

Não. Essa é a maneira subjetiva que eu e o Mentawai encaramos IoC e DI. Não é a palavra final sobre o assunto, mas tenho meus argumentos para defende-la.

Eu prefiro considerar DI como auto-wiring e acreditar que na grande maioria dos casos DI é utilizado juntamente com IoC.

Let’s go… :slight_smile:

IoC não refere-se estritamente a criação de instâncias, nem gerenciamento através de um único lugar (mesmo não entendendo bem o que você quis dizer com isso), nem com configurações da sua aplicação, nem com esses escopos citados. Na realidade, IoC é tão abrangente que nem restrita a OO está. Se você já escreveu algum event listener de um button no VB, você já usou IoC. Tá aí um exemplo prático. E não vimos escopos e nem configurações.

Nanão… DI é uma forma de IoC. Meu event listener do VB é outra forma. Quem faz a injeção (suponho que seja o que tu chamas de auto-wiring) é o container (tanto faz se você usa um conhecido como Spring, PicoContainer, Guice ou se desenvolveu o seu). Ou seja, DI estabelece que seu componente não vai usar um Locator para buscar suas dependências. Em algum momento até que o componente precise de uma dependência, esta será injetada nele. Como se descobre a dependência, instancia, injeta é mais um problema de projeto/implementação.

Não é um ataque ao Mentawai. Aliás é um framework pelo qual tenho bastante respeito. Porém, olhando no site do Menta (já faz bastante tempo) me parecia haver uma confusão entre esses conceitos. Se bem me lembro, acho que apenas um filtro de DI já bastava. Certamente nem a sua nem a minha são as palavras finais (e acho que a de ninguem seja). E, por favor, para o bem do post e crescimento geral da nação, use-os (seus argumentos) para defendâ-la.

Novamente, DI é uma forma de IoC. O que você chama de auto-wiring? É que o Spring também possui esse conceito e parece que você o está usando em outro sentido.

Make love, don’t make flamewar… :thumbup:

Martin Flower escreveu:

The basic idea of the Dependency Injection is to have a separate object, an assembler, that populates a field in the lister class with an appropriate implementation for the finder interface, resulting in a dependency diagram along the lines of Figure 2

Se esta é a idéia basica do DI como ela não “refere-se estritamente a criação de instâncias”??

No paragrafo abaixo vc ainda escreveu:

Nanão… DI é uma forma de IoC. Meu event listener do VB é outra forma. Quem faz a injeção (suponho que seja o que tu chamas de auto-wiring) é o container (tanto faz se você usa um conhecido como Spring, PicoContainer, Guice ou se desenvolveu o seu). Ou seja, DI estabelece que seu componente não vai usar um Locator para buscar suas dependências. Em algum momento até que o componente precise de uma dependência, esta será injetada nele. Como se descobre a dependência, [color=red][size=18]instancia[/size][/color], injeta é mais um problema de projeto/implementação.

[quote=Abdon]
Se esta é a idéia basica do DI como ela não “refere-se estritamente a criação de instâncias”??

No paragrafo abaixo vc ainda escreveu:

Nanão… DI é uma forma de IoC. Meu event listener do VB é outra forma. Quem faz a injeção (suponho que seja o que tu chamas de auto-wiring) é o container (tanto faz se você usa um conhecido como Spring, PicoContainer, Guice ou se desenvolveu o seu). Ou seja, DI estabelece que seu componente não vai usar um Locator para buscar suas dependências. Em algum momento até que o componente precise de uma dependência, esta será injetada nele. Como se descobre a dependência, [color=red][size=18]instancia[/size][/color], injeta é mais um problema de projeto/implementação. [/quote]

Um exemplo sem instanciação: o assembler pode buscar a dependência num JNDI da vida e injetar um stub em um componente.

Outra coisa, eu acho que as definições do Saoj nao estao certas. IoC eh uma característica geral (ate definidora, talvez) de frameworks quaisquer. Simplesmente significa que o código do framework vai chamar os seus métodos, e nao o contrario. Como o TheMask disse, isso existe ateh em toolkits gráficos procedurais (onde chamam de “callback”).

DI aplica inversion of control para controlar as dependencias dos seus objetos. Ou seja, em vez do objeto (pode chamar de componente se quiser) instanciar direto ou pedir para um locator, ele define um metodo (ou construtor) que sera chamado pelo framework para fornecer estas dependências.

O artigo do Fowler explica tudo isso em detalhes; so nao se preocupem demais em entender Interface Injection (“type 1”), acho que ninguem mais usa isso.

Obrigado pela explicação, Rafael. E muito obrigado por ter me lembrado de duas coisas: o termo callback (tinha me fugido durante o post :slight_smile: ) e de esclarecer que usei componente em um sentido amplo no qual objeto é um tipo deste, exatamente como você o usou no teu post.

IoC = Inversão de Controle = a responsabilidade pela criação das instâncias passa para um outro lugar, ou seja, o container de IoC. O nome não fala nada relacionado a injection, ou seja, a instancia criada pode ser injetada ou buscada por quem precisa dela.

DI = Injeção de Dependências = definição controvérsia = as palavras Injeção e Dependencia aparecem bem claramente no nome, logo considero que seja isso mesmo ou seja, a injeção das dependencias de um objeto, ou seja, auto-wiring de dependencias.

Injection = palavra vaga que pode não ter nada haver com IoC ou DI. Eu posso simplesmente criar uma instancia e injetar numa outra via reflection que não estarei fazendo nada relacionado com IoC ou DI.

Essa definição é controversa, mas eu prefiro considerar que:

IoC = criação de componentes que podem ser injetados ou não em algum lugar… (mais sobre isso aqui)

DI = AUTO-WIRING (interligamente automático), ou seja, injeção automática das dependencias de um objeto.

Injection = Nome vago, que significa apenas injetar qualquer coisa dentro de outra, geralmente por reflection, setter, etc.

Qual seria uma definição alternativa para os itens acima?

Uma dúvida: a inversão de controle se refere apenas a criação de instâncias? Até onde eu sabia, IoC era pré-requisito para rotular um software como “framework”, e não só pela instanciação, mas pela invocação destes objetos também…

Agrupei teus conceitos para uma melhor coesão. Comento-os logo abaixo.

IoC é vago. Não é apenas relacionado a DI. Também não é apenas relacionado a instanciação de objetos. Releia meu penúltimo post, por favor.

Autowiring, para mim, é isto. E existe DI sem autowiring, como pode ser visto no mesmo link (mode: no).

Por que isto não é DI?

Se esta qualquer coisa instanciada for dependência da outra, por que não é DI? Reflection, setter, etc são modos de fazer isso.

Pode ser por aí tb…

Se eu injeto uma instancia dentro de outra, então eu posso afirmar que havia uma dependencia aí… Pensando assim isso poderia ser DI, como vc falou…

Acho então que eu errei quando eu falo que DI = Auto-wiring.

Eu prefiro pensar em DI como uma injeção de dependencia pré-especificada, exemplo:


di("connection", Connection.class).source("connection");

Qualquer objeto requisitado do IoC container será checado pela dependencia acima. Se essa dependencia houver, uma “connection” será obtida do IoC container e será injetada no objeto requisitado. Isso é auto-wiring. Se é DI tb aí já não sei mais…