Interfaces Fluentes - Revista .net Magazine 95
O objetivo deste artigo é discutir o que são interfaces fluentes. Isto será feito através da apresentação dos benefícios oferecidos por este conceito, o qual fornece as bases necessárias para a construção de um código-fonte extenso
Em que situação o tema é útil:
Interfaces fluentes pode ser um recurso de grande valia na elaboração de classes que resultem na obtenção de um código mais simplificado. Métodos executados sequencialmente a partir de um objeto e que se espalhariam por diversas linhas, podem quando o tipo em uso implementar este conceito, vir a ser encadeados em uma única instrução. Dive rsos frameworks de larga aceitação no mercado empregam esta técnica: LINQ e o Fluent NHibernate constituem alguns exemplos.
Interfaces Fluentes
Projetando classes para um código-fonte mais simplificado A construção de classes básicas com funcionalidades consumidas por toda uma aplicação, corresponde a um tipo de ocorrência bastante comum. Em diversos casos, a implementação de uma operação envolverá a escrita de uma sequência de instruções envolvendo um objeto específico; tal situação pode produzir extensos blocos de comandos. Interfaces fluentes propõem alternativas para simplificar isto, buscando assim, a obtenção de um código mais enxuto e de rápida assimilação.
Os primeiros programas de computador nada mais eram do que um conjunto de instruções dispostas numa sequência lógica. Não eram incomuns trechos repetidos ao longo de um bloco código, assim como o uso extensivo de instruções desviando o fluxo de execução como resposta a determinadas condições (GOTOs). A este tipo de prática deu-se o nome de "código spaghetti". O desenvolvimento de aplicações segundo este modelo, se revelou mais adiante como uma tarefa trabalhosa, sobretudo, com o aumento da complexidade dos sistemas informatizados no decorrer do tempo.
A programação estruturada surgiu como uma solução às dificuldades desse estágio inicial do desenvolvimento de software. Estruturas de decisão e repetição, além da divisão de conjuntos de instruções relacionadas em sub-rotinas, foram alguns dos mecanismos introduzidos por este paradigma. Estas construções possibilitaram, através de uma melhor organização do código-fonte, a elaboração de poderosas aplicações atendendo aos mais variados objetivos.
Grandes avanços no hardware dos computadores também foram acompanhados, posteriormente, pelo advento de novas técnicas dentro da área de software. A Orientação a Objetos (OO) despontou como uma evolução da programação estruturada, dando uma grande ênfase à representação de elementos do mundo real como objetos formados por um agrupamento de características (atributos/propriedades) e comportamentos (operações). Tudo isso contribuiu, consequentemente, para uma melhor modelagem dos sistemas formulados em conformidade com tais conceitos.
Um dos grandes trunfos da Orientação a Objetos foi, sem sobra de dúvidas, o excelente trabalho efetuado por especialistas ao redor do mundo em torno de soluções a que se convencionou chamar de padrões de projetos (design patterns). Um pattern nada mais é do que um conjunto de recomendações que procura oferecer alternativas a uma demanda específica de desenvolvimento. Seguir diretivas deste tipo contribui para uma melhor estruturação das aplicações de software, assim como torna possível o reuso de um mecanismo de eficácia comprovada em projetos anteriores.
Padrões não devem ser encarados como uma garantia de obtenção de estruturas enxutas durante o processo de desenvolvimento de software. Muito embora as numerosas diretrizes fornecidas pela Orientação a Objetos levem à implementação de soluções seguindo boas práticas, ainda existirão trechos de código extensos e que executam operações sobre objetos através de uma lógica complexa.
Interfaces fluentes é uma maneira de simplificar a execução sequencial de funcionalidades disponibilizadas por um objeto. Trata-se de uma técnica que permite, basicamente, o agrupamento de um conjunto de chamadas a uma instância em uma única instrução. Classes concebidas segundo este padrão, dispensam os desenvolvedores de referenciar a todo o momento uma mesma estrutura, além de tornar mais conciso e legível o código-fonte que define um determinado comportamento.
A finalidade deste artigo é discutir de que maneiras classes OO dotadas de interfaces fluentes podem ser construídas, apresentando ainda diretrizes e benefícios decorrentes de tal abordagem. Com o objetivo de demonstrar este processo, será criada uma aplicação ASP.NET MVC de exemplo, a qual acessará um banco de dados SQL Server. O site em questão fará uso da implementação de um mecanismo de mapeamento objeto-relacional baseado em stored procedures e cuja principal classe conta com uma interface fluente. A biblioteca que contém estas funcionalidades de ORM também emprega expressões lambda (LINQ) para mapear o relacionamento entre campos de tabelas e propriedades de objetos, além de Reflection e recursos do ADO.NET.
Nota Frameworks
ORM ( “Object-relational mapping” - ou “Mapeamento objeto relacional”) permitem
a representação de estruturas de bancos de dados sob a forma de classes. Alguns
exemplos de mecanismos ORM populares são o Entity framework (o qual também
integra a plataforma .NET) e o NHibernate (ferramenta gratuita baseada no
Hibernate da plataforma Java).
Programação Fluente: uma visão geral
Interface fluente (ou em inglês “fluent interface”) é um termo criado pelos especialistas de software Martin Fowler e Eric Evans, sendo utilizado para descrever um padrão para a construção de classes que favorece a obtenção de um código menos extenso e mais legível. O acesso a diversas operações de um mesmo objeto, sucessivamente, é algo extremamente comum em atividades de desenvolvimento. Isto pode levar, à obtenção de extensos blocos de código e que impedem, devido a tal característica, uma rápida leitura e entendimento do cenário que se está considerando.
Sendo mais um pattern da Orientação a Objetos, o conceito de interface fluente não está restrito à plataforma .NET, podendo também se aplicar a estruturas concebidas em Java, por exemplo. Interfaces fluentes baseiam-se em uma técnica conhecida como "method chaining" (algo como "encadeamento de métodos", em português): caso diversas operações de um mesmo objeto precisem ser invocadas uma após a outra, a implementação de um tipo que permita encadear seus métodos torna possível a execução de tal processo por meio de uma única instrução.
Na Listagem 1 é apresentado um exemplo de classe que não implementa o conceito de interface fluente. Como pode ser observado, o tipo NotaFiscal conta com funcionalidades para o cálculo dos valores totais de uma nota fiscal, com a execução dos métodos correspondentes devendo acontecer em uma ordem específica a partir de uma instância de NotaFiscal (conforme indicado na Listagem 2).
Nota Method
chaining (ou "encadeamento de métodos") é uma técnica OO em que
múltiplos métodos são invocados sucessivamente,
a partir de uma instância inicial de um objeto. A fim de permitir que
uma operação seja executada imediatamente após a outra, métodos que
possibilitam este tipo de comportamento devolvem uma referência que aponta para
o próprio objeto que se está manipulando naquele momento.
Listagem 1. Classe que não emprega o conceito de interface fluente
...
public class NotaFiscal
{
public void CalcularVlTotalProdutos()
{
// Instruções para cálculo do valor
// total dos produtos
...
}
public void CalcularVlBaseIPI()
{
// Instruções para cálculo do valor
// da base do IPI
...
}
public void CalcularVlIPI()
{
// Instruções para cálculo do valor do IPI
...
}
public void AplicarDesconto(decimal percentual)
{
// Aplicar percentual de desconto sobre
// o total dos produtos
...
}
public void CalcularVlBaseICMS()
{
// Instruções para cálculo do valor
// da base do ICMS
...
}
public void CalcularVlICMS()
{
// Instruções para cálculo do valor do ICMS
...
}
public void CalcularTotalNotaFiscal()
{
// Calcular total da nota considerando
// descontos e tributos que deverão ser
// somados ao mesmo
...
}
}
...
Nota Lambda
expression é uma espécie de função anônima, ou seja, uma estrutura que conta
com um corpo (formado por uma ou mais expressões), mas que não possui um nome e
uma organização similar, àquela normalmente presente em métodos comuns.
Trata-se de um recurso bastante utilizado como meio para a passagem de
parâmetros a outras operações, sem que seja necessária a escrita de construções
num formato convencional. Geralmente uma lambda expression é formada por uma
instrução curta e, em muitos casos, não excedendo uma linha de código, fato que
representa uma interessante vantagem ao evitar que numerosas funções simples
precisem ser implementadas ao longo de uma classe.
Listagem 2. Exemplo de uso de uma classe sem o conceito de interface fluente
...
NotaFiscal notaFiscal = new NotaFiscal();
notaFiscal.CalcularVlTotalProdutos();
notaFiscal.CalcularVlBaseIPI();
notaFiscal.CalcularVlIPI();
notaFiscal.AplicarDesconto(vlPercDesconto);
notaFiscal.CalcularVlBaseICMS();
notaFiscal.CalcularVlICMS();
notaFiscal.CalcularTotalNotaFiscal();
...
O equivalente ao uso do tipo NotaFiscal seguindo um padrão fluente é demonstrado na Listagem 3. Os diversos métodos da classe em questão estão “encadeados” em tal instrução, já que foram implementados em NotaFiscal de um modo que os dispensa da obrigação de referenciar repetidamente a mesma instância. Essa é uma forma mais elegante e, portanto, enxuta de reescrever o código que consta na Listagem 2.
Listagem 3. Exemplo de uso de uma classe baseando-se no conceito de interface fluente
...
NotaFiscal notaFiscal = new NotaFiscal()
.CalcularVlTotalProdutos()
.CalcularVlBaseIPI()
.CalcularVlIPI()
.AplicarDesconto(vlPercDesconto)
.CalcularVlBaseICMS()
.CalcularVlICMS()
.CalcularTotalNotaFiscal();
...
A criação de classes dotadas de uma interface fluente acontece tomando-se por base as seguintes diretrizes e recomendações:
• Métodos que possibilitem o encadeamento de instruções devem retornar, obrigatoriamente, uma instância da própria classe na qual foram definidos;
• A instância devolvida como resultado da execução de um método, corresponde exatamente à referência que serviu de base para o seu acionamento. Logo, diz-se que o objeto está se auto-referenciando quando da ocorrência de construções que levem ao encadeamento de operações;
• Serão métodos sem um retorno específico (void) que se prestarão à aplicação de técnicas de programação fluente. Isto não significa que o tipo considerado não contará com outras operações que devolvam valores primitivos ou referências de objetos;
• Uma boa prática de implementação, consiste na separação dos métodos envolvidos na definição de um contexto fluente em uma interface. A partir disso se impede, em grande parte dos casos, que outras estruturas que dependam de uma classe fluente sofram efeitos colaterais quando da realização de alterações na mesma, além de não dificultar a inclusão de novos comportamentos à lógica pré-existente;"
[...] continue lendo...Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo