Pesquisar

sexta-feira, 30 de novembro de 2007

Fluent Interface ...

Primeiro a definição depois os exemplos.

*DSL ==> *é uma linguagem (mini liguagem) projetada para um tipo especifico de tarefa, isto é justamente o contrário de linguagens para proposito geral como Java, C ou C#.
*Fluent Interface (Interface Fluente)* ==> objeto que é capaz de deixar as suas responsabilidades mais expressivas a linguagem. (:S confuso, mas o exemplo ajudará)

Para se aprender algo nada melhor do que exemplos./ (aprender com exemplos não dá sono de acordo com Fowler, eu acho que ele está certo)/
Irei apresentar aqui dois exemplos: um simples e outro mais interessante.

*Exemplo Simples*

Supondo que tenho um objeto que representa o conceito Carro.

public class Carro{
private String nome;
private String marca;
private int portas;
public Carro(){
}
// métodos de acesso as propriedades encapsulados...
}

Quando fossemos "usar" esse objeto fariamos...

//***
Carro fusca = new Carro();
fusca.setNome("fusca");
fusca.setMarca("VW");
fusca.setPortas(2);
//***

Tentando aplicar o conceito de Interface Fluente, definiriamos uma Interface

public interface ICarro{
ICarro setNome(String nome);
ICarro setMarca(String nome);
ICarro setPortas(int nome);
}


//classe que implementa essa interface.
public class Carro implements /ICarro/{
private String nome;
private String marca;
private int portas;
public Carro(){
}

public ICarro setNome(String nome){
this.nome = nome;
return this;
}
public ICarro setMarca(String nome){
this.nome = nome;
return this;
}
public ICarro setPortas(int numero){
this.portas = numero;
return this;
}

}

*Agora nosso mesmo exemplo.( O simples ainda )*

//** ANTIGO
Carro fusca = new Carro();
fusca.setNome("fusca");
fusca.setMarca("VW");
fusca.setPortas(2);
//**

//** COM O CONCEITO DE INTERFACE FLUENTE
Carro fusca = new Carro();
fusca.setNome("fusca")
.setMarca("VW")
.setPortas(2);
//Note como cada método de set retorna o objeto aplicando outro método,
dando mais expressividade
//a linguagem.
//**

Isso parece meio bobo, mas para um *exemplo inicial* é até "bonzinho".


*Exemplo Interessante

*Outro possível exemplo, um criador de sql. Em tempos que o padrã JPA está se consolidando, se trata de exemplo não muito usual (sem bem que se pode usar-lo para criar as JPQL)... mas ao exemplo.
Se quiser "conversar" com o SGBD expresse em SQL. Uma consulta SQL é
similar ao exemplo abaixo:*

SELECT* campo1,campo2, campo4 (ou * para todos)
*FROM* tabela1
*[INNER | OUTER ...] JOIN* tabela2 *ON*
*WHERE* condicao1
*AND *condicao2
*OR* condicao2
*ORDER BY* campo1, campo2 ....

O exemplo acima não mostra todas as potencialidades da linguagem SQL mas serve para o propósito do exemplo.

1º A criação da Interface

public interface IConsultaSql{
IConsultaSql select(String campos);
IConsultaSql from(String tabela);
IConsultaSql innerJoin(String tablea);
IConsultaSql outterJoin(String tablea);
IConsultaSql on(String condicao);
IConsultaSql where(String condicao);
IConsultaSql and(String condicao);
IConsultaSql or(String condicao);
IConsultaSql orderBy(String campos);
}

Logo após a criação da classe que implementa a interface.

public class ConsultaSql implements /IConsultaSql/{
private StringBuilder construtor = new StringBuilder();
//note que o próprio StringBuilder aplica conceitos de interface fluente.
public ConsultaSql(){
}

public IConsultaSql select(String campos){
construtor.append("SELECT ")
.append(campos);
return this;
}

public IConsultaSql from(String tabela){
construtor.append(" FROM ")
.append(tabela);
return this;
}

public IConsultaSql innerJoin(String tabela){
construtor.append(" INNER JOIN ")
.append(tabela);
return this;
}
public IConsultaSql outterJoin(String tabela){
construtor.append(" OUTTER JOIN ")
.append(tabela);
return this;
}
public IConsultaSql on(String condicao){
construtor.append(" ON ")
.append(condicao);
return this;
}
public IConsultaSql where(String condicao){
construtor.append(" WHERE ")
.append(condicao);
return this;
}
public IConsultaSql and(String condicao){
construtor.append(" AND ")
.append(condicao);
return this;
}

public IConsultaSql or(String condicao){
construtor.append(" AND ")
.append(condicao);
return this;
}
public IConsultaSql orderBy(String campos){
construtor.append(" ORDER BY ")
.append(condicao);
return this;
}

public String getSql(){
String retorno = construtor.toString();
return retorno;
}
}

*Veja o uso.*

ConsultaSql con = new ConsultaSql();
con.select("nome,telefone")
.from("pessoa_fissica pf").innerJoin("contatos ct").on("pf.id=ct.pf_id")
.where("pf.nome like %?%")
.and("pf.idade>18").orderBy("nome,idade");

*Bem mais expressivo... mais flexível*

Senão engano o Hibernate está implementando [ou tem implementado] algo assim para criar os
objetos Criteria.

public String getSql() throws SqlIncorretoException{
String retorno = construtor.toString();
Sql.valida(retorno);
return retorno;
}


Uma nova característica do java 5, o varargs também pode ajudar a aplicar "esses novos conceitos" de interface fluente.

*TRADICIONALMENTE*
Produto bola;
Produto cafe;
Produto monitor;
Compra compra = new Compra(cliente);
compra.adicionarItem(bola);
compra.adicionarItem(cafe);
compra.adicionarItem(monitor);

*COM USO DE VARARGS
*
Produto bola;
Produto cafe;
Produto monitor;
Compra compra = new Compra(cliente);
compra.adicionarItem(bola,cafe,monitor);

Enfim são todos conceitos muito abstratos e ainda em discussão, logo "nada" é certo sobre esse tema. No mínimo o assunto é interessante e intrigante para os desenvolvedores e clientes (quem realmente interessa). Se acostume com esse novo paradigma /expressividade no desenvolvimento. (tudo mais perto da linguagem de
domínio do sistema)

/ps: perdoem os erros de português.
/Links interessantes sobre os assuntos/.

* _http://www.fragmental.tw_ (Blog sobre pesquisa em DSL)
* _http://martinfowler.com/bliki
/FluentInterface.html_ (Fowler
"ditando" sobre o que é uma Interface Fluente)
* _http://www.infoq.com/presentations/domain-specific-languages_
(Vídeo com uma introdução sobre DSL)

2 comentários:

Eder disse...

Muito interessante, parabens pelo artigo.
Consegui agora ver como realmente funciona.

Abraço

Anônimo disse...
Este comentário foi removido por um administrador do blog.