segunda-feira, 25 de fevereiro de 2008

Injeção de dependências

Breve. Espero :)

No Merlin, a ligação de regras de negócio aos elementos de IU é feita através de anotações, mais especificamente pela anotação @Agent, cujo uso pode ser visto abaixo:

public class Cliente {

@Agent(event = {"focusLost"} , action ] {"fillEmail"} )
String nome;

String email;
}

Neste trecho de código, está sendo definido um tratador para o evento de perda de foco no controle de tela que armazena o nome do cliente. Quando este evento ocorrer, o método de negócio fillEmail() é invocado.

Observa-se que, como o Merlin usa listas invertidas baseadas em proximidade, não é necessário especificar onde esse método de negócio reside (exceto no cas0 de colisões de nomes - as quais são devidamente reportadas tanto em tempo de projeto, de compilação ou de execução, conforme o caso).

Da mesma forma, é transparente se esse método é um método de uma classe (de qualquer visibilidade ou escopo), um webservice, um método de EJB ou mesmo nativo (novamente, são inferências e, em caso de ambigüidades, detalhamentos devem ser realizados).

O detalhe presente é: Como são passados os parâmetros para que o método fillEmail() seja executado ?

Hoje, o Merlin tem métodos utilitários, e uma possível implementação de fillEmail() seria:

public class AlgumaCoisa {

void fillEmail() {

JTextField nome = (JTextField) MerlinUtil.getControle("cliente.nome");
JTextField email = (JTextField) MerlinUtil.getControle("cliente.email");

email.setText( nome.getText().trim() + "@3layer.com.br");
}

Essa abordagem funciona sem problemas. Entretanto, a implementação fica dependente do pacote gráfico (no caso, o Swing) e a quantidade de código burocrático para recuperar os controles de tela pode ser demasiada.

Injeção de dependências, Groovy e Seam

Visando facilitar as coisas (e também deixar o código transparente quanto ao pacote gráfico), uma versão com injeção de dependências e recuperação automática de contexto, implicaria em um código como:


public class AlgumaCoisa {

@In
Context ctx;

void fillEmail() {

ctx.eval("$email.text = $nome.text.trim + '@3layer.com.br'");

}

ou

public class AlgumaCoisa {

@In
JTextField txtEmail;

@In
JTextField txtNome;

void fillEmail() {

txtEmail.setText(txtNome.getText().trim() + "@3layer.com.br");


}

Todas as três implementações de fillEmail() fazem exatamente a mesma coisa. O diferencial das duas últimas é que o contexto do formulário do cliente foi injetado automaticamente no método fillEmail(), de forma que a recuperação dos valores existentes na tela seja facilitada.

Na segunda implementação, código Groovy é executado e, portanto, nenhuma dependência de pacote gráfico existirá. Observa-se que a variável Context é do Merlin, e armazena toda a conversação do formulário.

Na terceira implementação, o programador possivelmente desejou uma maior clareza sintática, e assim, ele fica dependente do pacote gráfico.

A anotação @In é "herdada" do JBoss Seam. Com essa abordagem, estamos atentos à JSR 299, que acredito ter um draft ainda este ano.

Conclusões

A injeção de recursos é uma realidade hoje e uma tendência para o futuro. Agregada à flexibilidade de linguagens de scripting, como o Groovy, códigos que usam recursos de IU tendem a ficar cada vez mais transparentes e, quem sabe, realmente independentes de pacotes gráficos.

No exemplo dado (na segunda implementação), o método fillEmail() funcionaria sem problemas na maioria dos pacotes gráficos existentes.