在Composite结构上使用Interpreter模式

Ste*_*TNT 10 java design-patterns composite interpreter-pattern

我被要求使用Composite,Recursive Descendent ParserInterpreter创建表达式求值程序.

这是语法:

<cond> ? <termb> [OR <termb>]*
<termb>?<factb>[AND <factb>]*
<factb>?<expr> RELOP <expr> | NOT <factb> | OPAR <cond> CPAR
<expr> ? [PLUS | MINUS] <term> [(PLUS <term>) | (MINUS <term>)]*
<term> ? <termp> [(MULT <termp>) | (DIV <termp>) | (REM <termp>)]*
<termp> ? <fact> [POWER <fact>]*
<fact> ? ID | NUM | OPAR1 <expr> CPAR1
----TERMINALS----
ID ? ("A" | ... | "Z" | "a" | ...| "z") [("A"| ... | "Z" | "a" | ...| "z" | "0" | ... | "9")]*
NUM ? ("0" | ... | "9") [("0" | ... | "9")]*
OPAR ? "("
CPAR ? ")"
OPAR1 ? "["
CPAR1 ? "]"
RELOP ? EQ | NEQ | GT | GE | LT | LE
EQ ? "= ="
NEQ ? "!="
GT ? ">"
GE ? ">="
LT ? "<"
LE ? "<="
POWER ? "^"
DIV ? "/"
REM ? "%"
MULT ? "*"
MINUS ? "?"
PLUS ? "+"
AND ? “and” or “&&”
OR ? “or” or “||”
NOT ? “not” or “!”
Run Code Online (Sandbox Code Playgroud)

作业是:

基于Composite,Recursive Builder和Interpreter的项目目标是获取条件表达式,进行语法分析并构建其复合树.从树开始,您必须根据包含内部变量值的外部上下文(从属性文件中读取)来评估条件的结果

现在,我注意到的第一件事就是Interpreter使用了Composite结构,因此使用evaluate(:Context)方法扩展Composite结构似乎是个好主意.

我已经问过了,但我被告知这不是做任务的方法.好像我已经构建了一个解释器树,从复合树开始(这对我来说是非常不可见的,因为我已经有了一棵树可以使用了!).

所以我使用Composite + Recursive Builder构建了我的树,它识别输入并构建树而没有任何问题.

但问题是:如何将Interpreter应用于我的结构?

这是我的班级图(有些东西是意大利语,但这是可以理解的)

Composite + Builder类图

如果我做对了,Interpreter会为每个语法规则使用一个类,所以我必须创建一个cond类,然后是一个termb等等.

但我可以将它们链接到我的复合材料吗?

jef*_*eff 11

不知道为什么你被告知不要使用相同的树结构.我想我会在我的表达式接口中添加一个evaluate()方法.对于我,这说得通.表达式应该知道如何评估自己.

我会说你当前的表达式接口暴露太多(比如操作数).作为表达式的客户端,我只需要1)调用它,2)读取结果,我想也许3)打印它.实际上,我更喜欢使用toString()直接打印.

您可能已经注意到但并非所有表达式都采用2个操作数(例如NOT或NEGATE).这已经与您的界面产生了一种差异.我会简化它:

 public interface Expression {
   int evaluate();
 }
Run Code Online (Sandbox Code Playgroud)

然后,您的每个操作和终端都知道如何评估自己(并将自身转换为字符串).

所以我可以进行如下具体操作:

 public class Terminal implements Expression {
   private final int value;

   public Terminal(int value) { this.value = value; }

   public int evaluate() { return value; }

   public String toString() { return String.valueOf(value); }
 }

 public class Add implements Expression {
   private final Expression left;
   private final Expression right;

   public Add(Expression left, Expression right) {
     this.left = left;
     this.right = right;
   }

   public String toString() {
     return left.toString() + " + " + right.toString();
   }

   // leave the rest for you
 }
Run Code Online (Sandbox Code Playgroud)

现在我可以很容易地构建树

Expression expr = new Add(new Terminal(1), new Subtract(new Terminal(2), new Terminal(3)));

int result = expr.evaluate();
System.out.print(expr.toString() + " = " + result);
Run Code Online (Sandbox Code Playgroud)

我甚至不需要直接访问各个操作数.