19 de agosto de 2010

Design Patterns com Delphi : Interpreter - parte I

Apesar de não ser muito comum, pode aparecer entre as manutenções de um ERP a situação em que algo similar a uma linguagem tenha que ser desenvolvida. Por "linguagem" eu quero dizer uma sequência de comandos que sigam uma sintaxe bem definida, isto é, um conjunto de regras que devem ser respeitas quando escrevemos uma expressão nessa linguagem. É o mesmo conceito por trás de linguagens como o Pascal, C#, VB ou SQL em que cada comando dado deve seguir estritamente as regras estipuladas para a respectiva linguagem; caso contrário, a expressão não poderá ser avaliada já que ela não teria um significado associado.

Um exemplo seria o que ocorre com o cálculo de saldo disponível dos itens em estoque. Cada empresa tem um jeito próprio de verificar esse saldo, dependendo da necessidade. Alguns incluem a quantidade que está em produção e abatem a carteira de pedidos; há ainda tratamentos diferentes em relação à mercadoria que esteja "fora de estoque" (em beneficiamento ou em poder de terceiros, por exemplo), variando as combinações possíveis entre os tipos. Com isso, é possível construir uma sintaxe com operações simples - adição e subtração - e os nomes de cada tipo de variável (carteira de pedidos, em produção, etc.) como termos inerentes à linguagem. Se quiser, o usuário informa uma expressão para cada item (ou família de itens) respeitando a sintaxe e obterá o saldo conforme suas necessidades.

Este tipo de situação que envolve a construção de uma sintaxe é abordado pelo Design Pattern comportamental Interpreter, cujo foco está na representação das possíveis operações estabelecidas pela sintaxe. Isso significa que este padrão não se preocupa com a análise sintática de uma expressão mas sim com sua avaliação num determinado contexto, ficando a cargo da aplicação fazer a análise necessária para montar a lista de instâncias de classes que representam a expressão.

Segue um diagrama UML modelando o cenário que envolve cálculo de saldo através do padrão Interpreter, conforme descrito antes:
Diagrama UML para o padrão Interpreter

No quadro abaixo está a nomenclatura normalmente utilizada para as classes participantes da solução:
O Context contem informações globais que delimitam o cenário no qual uma expressão será computada. Cada parte da expressão pode buscar no contexto informações que a ajudem a determinar seu próprio valor. Ou seja, o valor retornado pela avaliação de uma expressão depende do contexto onde ela foi avaliada. A classe TWItem do diagrama tem essa responsabilidade.

AbstractExpression é uma interface que introduz os meios para avaliação de um termo qualquer de uma expressão da linguagem. No exemplo, a interface TWExpressaoAbstrata detem esse papel. Ela introduz a operação Calcular, que recebe um Contexto como parâmetro de modo que a mesma expressão pode ser avaliada em diversos contextos distintos.

TerminalExpression é o nome dado à um termo atômico da expressão, isto é, qualquer termo que não dependa da avaliação de outros termos para ter seu próprio valor avaliado. É o caso de variáveis e constantes numa linguagem. No exemplo desse post, representam expressões terminais as classes TWExpSaldo, TWExpPedidos e TWExpEmFabricacao pois seus valores são calculados com base apenas no contexto.

São classificados como NonterminalExpression os termos de expressões cujo valor depende do cálculo de outros termos. Se encaixam nessa definição as operações de adição e subtração previstas na sintaxe do exemplo; elas não são autocontidas e dependem da avaliação de outros dois termos. No exemplo, as operações citadas são implementadas respectivamente pelas classes TWExpSoma e TWExpSubtracao.

A classe Client é responsável por juntar todos os outros participantes da solução, construindo a árvore de instâncias que representam uma expressão e fornecendo um contexto apropriado para avaliar essa expressão quantas vezes forem necessárias. Este é o papel da classe TWEditaItem no diagrama.

Nos próximos posts eu apresento uma implementação desse diagrama em Delphi e também um exemplo de como analisar uma expressão na sintaxe estabelecida, transformando essa expressão em instâncias de classes que possibilitem avaliá-la em vários contextos.

Nenhum comentário :

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.