Inversão de controle X injeção de dependência

Eu tenho uma aplicação simples, onde eu estou usando struts.
A aplicação funciona da seguinte maneira. Eu tenho um Jsp que chama uma Action que chama um Facade que chama um Manager que chama um DAO
Sempre no Facade eu tenho que dar new no obj Manager e sempre no Manager eu tenho que dar new no obj dao …
Queria usar IOC ou injeção de dependência para resolver esse problema.

Alguem tem ae em exemplo disso feito sem o uso de algum frameWork?
Na verdade eu estou meio na duvida sobre o que é Inversão de controle e o que é injeção de dependência?

E ServiceLocator? é para que … hehehe?

Alguem sabe falar boas referencias sobre o assunto?

Vc disse sem usar framework, mas sugiro que estude spring, com ele voce consegue fazer e de uma maneira muito facil.

R.: É tudo a mesma coisa.

R.: É um pattern com objetivo de encapsular complexas chamadas de rede; busca de serviços (aqueles lookup chatos de ejb, por exemplo), etc.

mais detalhes: http://java.sun.com/blueprints/corej2eepatterns/Patterns/ServiceLocator.html

Mas veja que se você usar injeção de dependência (termo mais comum, pois inversão de controle as vezes confunde as pessoas), vai acabar eliminando o “service locator”, já que o objetivo da injeção de dependência é justamente esse, descobrir o objeto/serviço e “dar para você usa-lo”.

[quote=Icavalera]Eu tenho uma aplicação simples, onde eu estou usando struts.
A aplicação funciona da seguinte maneira. Eu tenho um Jsp que chama uma Action que chama um Facade que chama um Manager que chama um DAO
Sempre no Facade eu tenho que dar new no obj Manager e sempre no Manager eu tenho que dar new no obj dao …
Queria usar IOC ou injeção de dependência para resolver esse problema.

Alguem tem ae em exemplo disso feito sem o uso de algum frameWork?
Na verdade eu estou meio na duvida sobre o que é Inversão de controle e o que é injeção de dependência?
[/quote]

Inversão de controle é um principio de OO e significa que uma classe não deve controlar as suas dependências.
Ou seja, se A precisa de B, A não deve executar new B() (que é exactamente o que vc está fazendo). O que deve acontecer é que A
deve receber B no contrutor ou num método set. A diferença é que , se A precisa de B obrigatoriamente para executar o seu trabalho, B deve ser passado no contrutor e consistido para não ser null. Se A pode usar B opcionalmente então deve ser usado um set.

injeção de Dependencia é o processo que, dado A, executa os sets necessários para dar a A acesso a B. Ou seja, quando vc chama

a.setB(b)

Vc está injetando uma instância de B em A.
Isto é feito em uma terceira classe,C , o injetor. Esta classe faz o seguinte:

B b = new B();
A a = new A(b);

// ou 

A a = new A()
a.setB(b);

Injeção Automatica de Dependencia é o processo/mecanismo que realiza a injeção sem que vc tenha que escrever este tipo de codigo.
Framework de injeção Automática de Dependencia ou Container de Injeção (Automática de Depedencia) é um frameowrk onde vc declara quais objetos devem ser injetados em quais outros e o container executa a logica de criar os objetos e injetá-los no lugar certo.

O codigo anterior mostra como se faz injeção sem framework (sim, é o jeito normal de escrever OO! )

Usar um container de injeção facilita as coisas porque vc só tem que dizer o que quer e não como é feito o processo.Além disso o container trata de coisas como referencia ciclica e permite que vc modifque a criação dos objetos, como por exemplo criando proxies em torno do objeto real.

ServiceLocator é um padrão EE para descobrir objetos no registro JNDI. Todo o Container de Injeção atua como um servicelocator, a diferença
é que usando serviceLocator, vc, na classe A vai dar new do ServiceLocator, e mandar ele procurar o B. Ok, vc não dá new do B, mas dá do ServiceLocator, violando do mesmo jeito a inversão de controle. Este problema não é do serviceLocator em si, mas do jeito que se usava antigamente.
Hoje em dia, nada o impede de mandar injetar o proprio contexto de injeção em um objeto e localizar o objeto explicitamente. A diferença é vc nunca dará new nos objetos.

Na verdade inversão de controle (ioc - inversion of control) é um conceito que engloba injeção de dependencias (di - dependency injection), mas é bem mais abrantente.

ioc é o conceito que define frameworks, e significa que o framework chama o seu código (e não o contrario).
Por exemplo, quando colocamos um listener em um componente swing, isso é ioc, mas nao tem nada a ver com di

[quote=magnomp]Na verdade inversão de controle (ioc - inversion of control) é um conceito que engloba injeção de dependencias (di - dependency injection), mas é bem mais abrantente.

ioc é o conceito que define frameworks, e significa que o framework chama o seu código (e não o contrario).
Por exemplo, quando colocamos um listener em um componente swing, isso é ioc, mas nao tem nada a ver com di
[/quote]

É verdade. Apenas não é verdade que “ioc é o conceito que define frameworks”. Para fazer IOC não precisa de frameworks.

Concordo que para usar IoC não precisa de um framework. Mas o que eu quis dizer com “ioc é o conceito que define frameworks” é que o uso de IoC é o que diferencia um framework de uma biblioteca de classes.

Tem um exemplo de Injeção de Dependência então ? Sem FrameWork …

public class Cliente {
    private Dependencia dependencia;

    public Cliente(Dependencia dependencia) {
        this.dependencia = dependencia;
    }
}

public class Teste {
  public static void main(String[] args) {
    Cliente cliente = new Cliente(new Dependencia());
  }
}

Acabei de usar injeção de dependencia ali, e sem nenhum framework. Mais especificamente, isso é injeção pelo construtor. Existe tambem injeção via setter, e um outro tipo que não me lembro.

Eu desenvolvi um framework de DI para Delphi (http://www.emballo-di.com) que trabalha apenas com injeção via construtor. Tudo que ele faz é resolver os parametros do construtor e invoca-lo via reflexão.
Eu havia implementado um método de injeção que ele enumerava todos os atributos da classe e injetava em cada um, sem precisar usar nem um setter, mas posteriormente eu removi isso pois vi que não era muito bom injetar dessa forma

Olha só…no seu caso eu instanciaria o “Facade + Manager + DAO” tudo na Action.

Pelo o que vc disse sua Action esta instanciado o “Facade”. E depois vc não tem mais controle sobre o manager e o DAO pq essas instância são feitas internamente.

A Inversão de Controle sugere que você tenha o controle sobre os objetos. Se na sua Action vc fizer

DAO d = new DAO()
Manager m = new Manager(d);
Facade f = new Facade(m);

Então ainda na sua action vc possue o controle de todos os objetos. Lógico que vc pode evitar esses “news” atráves de outros patterns como proxy e factory. Mas aí são outros 500…

[quote=Giulliano]Olha só…no seu caso eu instanciaria o “Facade + Manager + DAO” tudo na Action.
[/quote]

Isso seria um erro crasso.
Primeiro vc está amarrando tudo na action, e segundo está violando a separação de camadas.

A injeção de depedências quando não é feita automaticamente, deve ser feita antes do sistema começar. no caso de aplicações web, deve acontencer no evento de inicialização da aplicação (ServletContextListener).

Como esta classe não pertence a nenhuma camada não ha problemas de dependência.

Você pode dar um exemplo prático baseado nisso que vc falou (e que siga a estrutura existente do projeto) ?

A injeção nem sequer existe aqui (quem dirá automaticamente). Além disso ele precisa de uma solução que não dependa de frameworks. Se ele seguisse o seu conselho eu recomendaria o uso de JNDI e lookups. (discorda ?)

Aqui eu não entendi o que vc disse. Qual classe não pertence a nenhuma camada e quem não tem problema de depêndencia?

Minha opnião foi baseada no seguinte raciocínio: O facade possui a inteligência das regras de negócio. Porém para ele ser executado é necessário injetar um Manager e um DAO. Portanto se minha aplicação fosse dividida em Swing e Web, na minha aplicação Swing ficaria a cargo do novo módulo injetar as depências necessárias para o funcionamento do facade. Aí entrando no conceito de proxy…para aplicações Swing eu poderia usar um Manager e um DAO diferente da web.

[quote=Giulliano][quote=sergiotaborda]
Isso seria um erro crasso.
Primeiro vc está amarrando tudo na action, e segundo está violando a separação de camadas.
[/quote]

Você pode dar um exemplo prático baseado nisso que vc falou (e que siga a estrutura existente do projeto) ?
[/quote]

Um exemplo de quê ?

Discordo. Primeiro, não ha nenhuma necessidade em usar frameworks. Segundo não ha necessidade em usar JNDI. Terceiro, mesmo com um injetor de dependencias automático vc não evita lookups ( evitar lookups é impossivel. É uma questão de quantos e quais).

Primeiro vc define um registro de objetos. Sim, pode usar JNDI para isto, mas não é estritamente necessário.

Segundo vc define um ServletContextListener e o registra no web.xml

Terceiro, no codigo de init do ServletContextListener vc inicializa os objetos e os registra no Registro , mais ou menos assim


public MyServletContextListener implements ServletContextListener  {

       public void contextInitialized(ServletContextEvent ctx) {

               // Inicializa DataSource
               Properties p = new Properties()
               p.load() // de um arquivo de proeprties 

               DataSource ds = new JDBCDataSource(p);

               Dao dao = new JdbcDao(ds);

               Manager manager = new SimpleManager(dao);

               Facade facade = new SimplesFacade(manager);

               Registry.setFacade(facade);

        }

}

// no action usaria assim

public classe Action{

   public void algumMetodo(){
        
         // lê parametros do request
          // ...

        // Faz algo com os parametros atraves do façade
        Facade facade = Registro.getFacade();

        facade,fazalgumaCoisa(parametroA,parametroB);
  }

}

Repare que todos os objetos são inicializados mas apenas o facade é colocado no registro.
Repare também que este codigo depende de todos os objetos. Isto significa que, pelas regras, esses objetos deveriam ser injetados nele também.
Poderiamos desenvolver um mecanismo de escolhe as classes via propreties ou algo assim, mas podemos tb pensar que esta classe é o limite do sistema. Ou seja, não ha como comandar a sua criação, logo ,não ha como comandar a sua injeção automática.

Eu estava falando da classe MyServletContextListener. Ela não pertence a nenhuma camada e o fato dela depender de todas as outras classes não é um problema.

Só uma curiosidade. Por que nao usar framework para fazer IoC?

Marco.

Sua solução não difere em praticamente nada de uma solução JNDI (que é muito mais robusta do que um simples Hash). Apenas o conceito de armazenagem e busca dos objetos que é diferente.

Acho que a única parte em que concordo com vc é que os objetos deveriam ser criados na inicialização da aplicação (mesmo assim ainda há controvérsias).

Portanto ao dono do tópico eu recomendo o uso de JNDI e Lookups. E a inicialização pode ser feita numa porrada só como foi feito pelo Sergio ou sob demanda (que eu prefiro).

[quote=Giulliano]
Portanto ao dono do tópico eu recomendo o uso de JNDI e Lookups. E a inicialização pode ser feita numa porrada só como foi feito pelo Sergio ou sob demanda (que eu prefiro).[/quote]

Sem usar uma ferramenta de IOC não tem como fazer uma inicialização sob demanda. Explique como vc faria/faz isso.

Note que num web-container não existe JNDI. Adicionar JNDI tem o mesmo custo que adicionar uma ferramenta IoC como o Spring ou o Guice.
(não vale dizer que o tomcat já vem com jndi ,porque o tomcat não são todos os webcontainers)

[quote=sergiotaborda]
Sem usar uma ferramenta de IOC não tem como fazer uma inicialização sob demanda. Explique como vc faria/faz isso.

Note que num web-container não existe JNDI. Adicionar JNDI tem o mesmo custo que adicionar uma ferramenta IoC como o Spring ou o Guice.
(não vale dizer que o tomcat já vem com jndi ,porque o tomcat não são todos os webcontainers)[/quote]

Sergio eu vou dizer exatamente isto: O Tomcat tem o JNDI e o Tomcat (acredito eu, até que se prove o contrário) é o ServletContainer mais usado nas empresas, faculdades, cursos e afins. E ainda que não seja um Tomcat a migração entrte esses servidores não é custosa.

Ainda assim não sabemos qual é o servidor que ele usa. Quem sabe não é um servidor JEE.

R.: É tudo a mesma coisa.
[/quote]

Não é não.

[quote=mrmarcondes]Só uma curiosidade. Por que nao usar framework para fazer IoC?

Marco. [/quote]

A idéia era aprender … hehehe
Mas parece que agora nessa nova especificação j2ee6 vai mudar tudo … hehe