Compartilhar via


Métodos Encadeáveis e a Fluent API: Quando e não Utilizá-los

 O conceito de Fluent Interfaces foi introduzido em um workshop por Eric Evans e Martin Fowler, os gurus da Engenharia de Software, em 2005. O que foi proposto por eles era a criação de APIs orientadas a objetos cujo código fosse mais fácil de ler. Seria necessário, assim, utilizar uma técnica chamada Method Chaining (ou encadeamento de métodos) para implementar tal conceito. Neste artigo eu ilustrarei em um exemplo explicando como se dá a implementação deste approach, assim como seus prós e contras. Por fim, você vai entender qual é a melhor situação para utilizá-lo ou evitá-lo.

A ideia central se baseia em simplificar o uso dos objetos, promovendo uma fluidez na escrita do código. Segundo Fowler, a principal razão para criar uma fluent API é seguir a mesma linha de qualidade de uma Domain Specific Language (DSL). Uma DSL é uma linguagem genérica que os desenvolvedores criam para resolver problemas específicos do domínio, quando na equipe há problemas de comunicação e entendimento acerca das complexas regras de negócio que o projeto pode trazer. Isto é, se uma API for bem planejada desde o início, será possível abstrair o problema de modo que a comunicação do domínio seja equivalente à linguagem natural que utilizamos na comunicação cotidiana.

Para não perder o foco, não vou me alongar a respeito de DSLs. Convido o leitor a clicar nos links no final do texto para se informar mais. O importante é que é possível mapear um modelo, um algoritmo, ou pseudocódigo em uma implementação “fluida”, em forma de expressão.

Mas, o que pode dar fluidez ao código? Segundo os autores do conceito, ao promover várias chamadas de métodos subsequentes a uma mesma instância de objeto temos um encadeamento de métodos; isso tudo em uma só expressão. A saber, para chamar um método precisamos primeiramente de um objeto que o defina. Depois, para garantir o encadeamento, cada método deverá retornar uma referência ao objeto da classe que o criou (this). O último método não precisa retornar this.

Criei uma aplicação de exemplo para contextualizar. Suponha que temos um voo e queremos saber seus dados (número do voo, origem, destino, a data e sua duração).

public class Flight

{

    ``string _origin;

    ``string _destination;

 

    ``DateTime _date;

 

    ``public int FlightID { get``; ``private set``; }

 

    ``public Flight(``int id) { ``this``.FlightID = id; }

 

    ``public static Flight CreateFlight(``int id)

    ``{

        ``return new Flight(id);

    ``}

 

    ``public Flight Origin(``string origin)

    ``{

        ``this``._origin = origin;

        ``return this``;

    ``}

 

    ``public Flight Destination(``string destination)

    ``{

        ``this``._destination = destination;

        ``return this``;

    ``}

 

    ``public Flight When(DateTime date)

    ``{

        ``this``._date = date;

        ``return this``;

    ``}

 

    ``public int Duration(``int hours)

    ``{

        ``return hours;

    ``}

}

/* Dados do Voo

 ``* Voo: 1234

 ``* Origem: SP

 ``* Destino: RJ

 ``* Data: Hoje

 ``* Duração: 1h

 ``*/

 

Flight.CreateFlight(1234).Origin(``"SP"``).Destination(``"RJ"``).When(DateTime.Today).Duration(1);

Como aspectos negativos dessa abordagem, posso dizer que uma expressão encadeada impossibilita o debugging. Além do mais, demora mais tempo para programar, e nem sempre seus métodos e classes são adaptáveis (a menos que você crie uma API do zero já planejando isso). Uma API feita à base de construtores, propriedades e métodos adicionais são bem mais fáceis de se escrever. Esse jeito de desenvolver APIs mostra que não faz sentido um método setter retornar um valor.

Se o intuito for de criar uma API pensando em auxiliar o trabalho do desenvolvedor, não é recomendável. Isso só acrescentará em termos de complexidade (mais código a ser escrito).

Entretanto, essa metodologia fornece interfaces mais simplificadas para invocação de métodos. Em alguns casos torna-se realmente necessário, como em testes unitários ou mocks para validar regras de negócio. Também, para validação de conceitos do domínio com stakeholders. Dois exemplos de fluent APIs são LINQ e NHibernate.

Para quem é iniciante, não confundir o assunto com Listas Encadeadas (Estruturas de Dados). Isso é outra coisa.

Como complemento, no jQuery é um pouco diferente. O encadeamento de métodos se dáapenas por “anexar” as chamadas de métodos um ao lado do outro, sobre um elemento. Dessa forma, o browser não precisa procurá-lo na página mais de uma vez.

No exemplo abaixo, suponha que você tem um quadrado de cor verde-musgo (no html) e um botão. Ao clicá-lo, a cor do quadrado muda para um tom de vermelho, é deslocado para cima, desaparecendo; por fim ele reaparece com um leve fade-in.

<``div`` ``id``=``"box"``; ``style``=``background``-color:#98bf21; height:100px; width:100px; position:absolute /div>

$(``function () {

  ``$(``"#btn"``).click(``function () {

    ``$(``"#box"``).css(``"background-color"``, ``"#cc2929"``).slideToggle(``"slow"``).fadeIn(``"slow"``);

   ``});

})

Um abraço e até a próxima,

Thiago