quarta-feira, 6 de outubro de 2010

Fluent Interfaces e operadores Lógicos

quarta-feira, 6 de outubro de 2010
Algo com que todos os desenvolvedores tiveram como problema é a multiplicade de operações repetidas, creio que um exemplo seja melhor.

Reparem neste trecho de código:
public class LocalizadorDeClientes{
    public List<cliente> buscarPorCPF(String cpf){
        //implementação da busca.
    }
    
    public List<cliente> buscarPorNome(String nome){
        // implementação da busca.
    }
}
O cliente solicita agora que a busca seja feita por cliente inadimplente, a implementação mais comum seria mais um método de pesquisa:
public List<cliente> buscarInadiplentes(){
...
}
Essa abordagem é ruim? Não necessariamente, mas podemos usar um esquema diferente, o cliente te solicita agora quero combinar os filtros, muitos diriam que não dá ou fariam métodos diversos para todas as combinações possíveis.

Para casos como estes em que queremos combinar comportamentos poderemos tirar proveito da fluent interfaces:

Os exemplos apresentados aqui foram feitos apenas para exemplificar a metodologia podendo variar em implementação.

Reparem no exemplo modificado, usando fluent interfaces:
public class LocalizadorDeClientes{
public LocalizadorDeClientes porCPF(String cpf){
//configura a busca para ser realizada por cpf
return this;
}

public LocalizadorDeClientes porNome(String nome){
//configura a busca para ser realizada por nome
return this;
}

public LocalizadorDeClientes inadimplente(){
//configura a busca para ser realizada por inadimplentes
return this;
}

public List<cliente> fazerBusca(){
//configura a busca para ser realizada por inadimplentes
return this;
}

}
o uso seria assim:
LocalizadorDeClientes buscador = new LocalizadorDeClientes();
buscador.PorCPF(numCPF).porNome("carlos").inadimplente().fazerBusca();
Reparem que agora você pode encadear a chamada, fazendo com que a busca por exemplo possa ser configurável.

Este exemplo pode ser estendido usando um esquema de operadores lógicos, bastaria adicionar os métodos na classe:
public LocalizadorDeClientes e(){
// configura a busca para executar com o operador e
// no hibernate seria um conjunction em memória seria um &&
return this;
}

public LocalizadorDeClientes ou(){
// configura a busca para executar com o operador ou
// no hibernate seria um disjunction em memória seria um ||
return this;
}

public LocalizadorDeClientes nao(){
// configura a busca para executar com o operador nao
// no hibernate seria um Restriction.not em memória seria um !
return this;
}
Agora poderia fazer as consultas por exemplo assim:
LocalizadorDeClientes buscador = new LocalizadorDeClientes();
buscador.PorCPF(numCPF).e().porNome("carlos").nao().inadimplente().fazerBusca();
um esquema como este de fluent interfaces permite compor comportamento complexo a partir de um conjunto de comportamentos simples, a projetos que já utilizam isso como o Calopsita isso foi até mesmo discutido recentemente o Tectura no tópico nomes Complexos/descritivos no modelo e Martin flower fala exatamente sobre isso em seu artigo sobre fluent interfaces.

Tente entender o que é fluent interfaces, e o seu uso com operadores lógicos, pois ajudam a ter um domínio mais rico em seu software.


Nenhum comentário :

Postar um comentário