Enrolação de dependências – parte III

Finalmente, a parte final deste artigo!

Antes de prosseguir, leia: https://cabritin.wordpress.com/2008/03/07/enrolacao-de-dependencias-parte-ii/

Observe novamente a figura publicada na parte 1:

O diagrama ilustra uma relação um-para-muitos entre empresa e funcionário, este podendo ser um gerente ou um empregado.

Vamos traduzir este diagrama em um pouco de código. Inicialmente, poderíamos implementá-lo da seguinte maneira:

public class Empresa {
    private List<Funcionario> funcionarios;

    public Empresa() {
        funcionarios = new ArrayList<Funcionario>();
    }

    public void addGerente() {
        funcionarios.add(new Gerente()); // Linha 9
    }

    public void addEmpregado() {
        funcionarios.add(new Empregado()); // Linha 13
    }
}

public interface Funcionario {

}

public class Empregado implements Funcionario {
    // Construtores, atributos, métodos, etc
}

public class Gerente implements Funcionario {
    // Construtores, atributos, métodos, etc
}

Há algum problema nessa implementação? Aparentemente, não. Ela está bonitinha, usando polimorfismo, inversão de dependências (lembra o que é?) e tudo o mais. Mas veja só: a classe Empresa está instanciando diretamente as classes Gerente e Empregado (linhas numeradas). Tá, mas e qual o problema nisso? Ora, simples: se por acaso os construtores dessas classes mudarem, precisaremos modificar também as linhas 9 e 13. Agora, imagine se eu tivesse 50 classes, todas dependendo de Empregado e Gerente! Ia sobrar pro estagiário fazer a modificação em todas elas…

Mas vamos facilitar a vida do estagiário. Vamos tentar aplicar Inversão de Controle à situação.

O que queremos, então? Queremos evitar que Empresa instancie Empregado e Gerente diretamente; queremos diminuir o acoplamento entre as classes. A criação das instâncias é a responsabilidade que queremos inverter, ou seja, deixar para outra entidade fazê-lo.

Resumindo: a classe Empresa não mais criará as instâncias; ela as receberá já criadas. Como? Através dos métodos addEmpregado() e addGerente(). Vamos modificá-la então!

public class Empresa {
    private List<Funcionario> funcionarios;

    public Empresa() {
        funcionarios = new ArrayList<Funcionario>();
    }

    public void addFuncionario(Funcionario f) {
        funcionarios.add(f);
    }
}

Nossa! A classe Empresa ficou totalmente independente dos tipos concretos de Funcionario. Ela nem sabe mais que eles existem! O código cliente que utilizar as classes de domínio usará a classe como se segue:


Empresa e = new Empresa();
e.addFuncionario(new Gerente());
e.addFuncionario(new Empregado());

Ou seja, os funcionários são agora injetados dentro da empresa através do método addFuncionario(). Espere um pouco, você disse injetados?

Sim. Utilizamos um método que serve para passarmos para a (injetarmos na) classe Empresa as instâncias (dependências) de que ela precisa – neste caso, os funcionários de uma empresa. Invertemos o controle da instanciação dos objetos para o código cliente. Isto é injeção de dependências.

Há outras formas de injetar dependências em uma classe, como por exemplo fazê-lo por meio de um construtor (passando a dependência como argumento). E há também outras formas de instanciar os objetos de que sua aplicação precisa: frameworks como o Spring e o PicoContainer implementam containers que cuidam do processo de instanciação. Se não quiser utilizar um desses containers, um Factory Method resolve seu problema muito elegantemente.

Para encerrar, sugiro fortemente que você leia o artigo do Martin Fowler sobre o assunto. Estes posts não têm a intenção de substituí-lo: serve apenas para dar uma idéia geral.

Até mais.

Anúncios
Enrolação de dependências – parte III

Um comentário sobre “Enrolação de dependências – parte III

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s