Padrão de Projeto Interpreter Kleinner Farias © LES/PUC-Rio Agenda • Propósito/Intenção • Motivação • Exemplo • Aplicabilidade • Estrutura • Participantes • Conseqüências • Implementação © LES/PUC-Rio Intenção • Afinal, qual é o propósito do Interpreter? Dada uma linguagem, definir uma representação para a sua gramática juntamente com um interpretador que usa representação para interpretar sentenças da linguagem. - • Interpreter descreve como definir uma gramática para linguagens simples, representar sentenças e interpretar estas sentenças. © LES/PUC-Rio Motivação • Quando devemos usar o padrão Interpreter? - Se um tipo específico de problema ocorre com freqüência suficiente, pode valer a pena expressar instâncias do problema como sentenças de uma linguagem simples. • Alguns Problemas: Como irei trabalhar com patterns of strings? Use o Padrão Interpreter. Algorítmos de busca podem interpretar uma expressão regular que especifica um conjunto de cadeias a serem encontrados. Como irei fazer pesquisa de caracteres? © LES/PUC-Rio Motivação • O Interpreter analisa o problema dividindo-o em pequenos pedaços, e então coloca os pedaços de volta juntos, como uma sentença numa linguagem simples. • Pattern matching – pesquisar cadeias de caracteres que correspondem a um determinado padrão. • Pattern of strings – expressões regulares • Match – algoritmo de busca © LES/PUC-Rio Exemplo BooleanExp ::= VariableExp | Constant | OrExp | AndExp | NotExp | '(' BooleanExp ')' AndExp ::= BooleanExp 'and' BooleanExp OrExp ::= BooleanExp 'or' BooleanExp NotExp ::= BooleanExp 'not' BooleanExp Constant ::= 'true' | 'false' VariableExp ::= 'A' | 'B' | ... | 'Z‘ • Onde temos: - Símbolos não-terminais: BooleanExp, AndExp, OrExp, NotExp. - Símbolos terminais: Constant, VariableExp © LES/PUC-Rio Aplicabilidade • Quando houver uma linguagem para interpretar e seja possível representar sentenças da linguagem como árvores sintéticas abstratas. • Quando ele funciona melhor? - A gramática é simples. - A eficiência não é uma preocupação crítica. © LES/PUC-Rio Estrutura © LES/PUC-Rio Participantes • AbstractExpression – declara uma operação que será comum a todos os nós na árvore sintática abstrata. • TerminalExpression – implementa operações definidas na AbstractExpression • NonTerminalExpression - para cada regra da gramática é necessário um NonTerminalExpression. - mantém variáveis de instância do tipo AbstratctExpression. - implementa uma operação Interpret. • Context - contém informação que é global para o interpretador. • Client – contrói ou recebe um árvore sintática. © LES/PUC-Rio Conseqüências • Facilidade de mudar e estender gramática – usa classe para representar regras da gramática. • Implementar a gramática também é fácil – os “nodos” da árvore são implementados de uma maneira similar. • Gramáticas complexas são difíceis de manter – para cada regra da gramática é definido uma classe. • Acrescentando novas formas de interpretar expressões – torna mais fácil resolver uma expressão de uma nova maneira. © LES/PUC-Rio Implementação • Criação da árvore sintática abstrata – o padrão não define como criar a árvore sintática abstrata. • Compartilhando símbolos terminais com o padrão FlyWeight – compartilhamento de símbolos terminais usando o padrão FlyWeight. • Flexibilidade – as classes podem ser alteras e modificadas facilmente. © LES/PUC-Rio Implementação © LES/PUC-Rio Implementação public class Context { private Hashtable context = new Hashtable(); } public void assign(String name, boolean val) { context.put(name, new Boolean(val)); } public boolean lookUp(String name) { return ((Boolean)context.get(name)).booleanValue(); } public Context() { } public interface BooleanExp { public abstract boolean evaluate( Context c ); public abstract BooleanExp replace(String var, BooleanExp exp); public abstract BooleanExp copy(); } © LES/PUC-Rio Implementação public class AndExp implements BooleanExp { private BooleanExp operand1; private BooleanExp operand2; public andExp (BooleanExp oper1, BooleanExp oper2) { operand1 = oper1; operand2 = oper2; } public boolean evaluate(Context c) { return operand1.Evaluate(c) && operand2.Evaluate(c); } public BooleanExp copy() { return new AndExp(operand1.Copy(), operand2.Copy()); } } public BooleanExp replace(String var, BooleanExp exp) { return new AndExp( operand1.Replace(var, exp), operand2.Replace(var, exp) ); } © LES/PUC-Rio Implementação public class VariableExp implements BooleanExp { private String name; public VariableExp(String _name) { name = _name; } public boolean evaluate(Context c) { return c.LookUp(name); } public BooleanExp copy() { return new VariableExp(name); } public BooleanExp replace(String var, BooleanExp exp) { if(var.equals(name)) { return exp.Copy(); } else { return new VariableExp(name); } } } © LES/PUC-Rio Implementação public class Test { public static void main(String[] args) { // Test : // (true and x) or (y and (not x)) Context context = new Context(); VariableExp VariableExp VariableExp VariableExp x = new VariableExp("X"); y = new VariableExp("Y"); bTure = new VariableExp("true"); bFalse = new VariableExp("false"); context.Assign("true", true); context.Assign("false", false); context.Assign("X", true); context.Assign("Y", true); } } BooleanExp expression = new orExp( new AndExp(bTure, x), new AndExp(y, new NotExp(x)) ); boolean result = expression.evaluate(context); System.out.println("The result is:" + result); © LES/PUC-Rio