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
Download

Slides