[工作中的设计模式]解释器模式模式Interpreter
一、模式解析
解释器模式是类的行为模式。给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。
以上是解释器模式的类图,事实上我很少附上类图,但解释器模式确实比较抽象,为了便于理解还是放了上来,此模式的要点是:
1、客户端提供一个文本、表达式或者其他,约定解析格式
2、针对文本中可以分为终结符表达式和非终结符表达式,
3、终结符表达式无需进一步解析,但仍需要转化为抽象接口的实例
4、针对非终结表达式,没一种标示需要定义一种解析类,如果后续有扩展,则进一步扩展一种解析类,并修改解析分支即可完成扩展
二、模式代码
1、定义整体环境类,保存除了解析器外,其他全局信息
package interpreter.patten; public class Context { private String input; private String output; public String getInput() { return input; } public void setInput(String input) { this.input = input; } public String getOutput() { return output; } public void setOutput(String output) { this.output = output; } }
2、定义抽象解析器
package interpreter.patten; public abstract class AbstractExpression { public abstract void interpret(Context context); }
3、定义终结符解析器
package interpreter.patten; public class TerminalExpression extends AbstractExpression { @Override public void interpret(Context context) { System.out.println("终结符解析器"); } }
4、定义非终结符表达式
package interpreter.patten; public class UnTerminalExpression extends AbstractExpression { @Override public void interpret(Context context) { System.out.println("非终结符解析器"); } }
5、定义客户端类
package interpreter.patten; import java.util.ArrayList; import java.util.List; public class Client { public static void main(String[] args) { Context context=new Context(); List<AbstractExpression> list=new ArrayList<AbstractExpression>(); list.add(new TerminalExpression()); list.add(new UnTerminalExpression()); list.add(new TerminalExpression()); list.add(new UnTerminalExpression()); list.add(new TerminalExpression()); list.add(new UnTerminalExpression()); for(AbstractExpression expression:list){ expression.interpret(context); } } }
6、客户端执行结果
终结符解析器
非终结符解析器
终结符解析器
非终结符解析器
终结符解析器
非终结符解析器
三、应用场景
以上模式代码完整的实现了类图中的所有内容,并打印出了结果,但是又显得毫无意义,看起来比较蠢,这是因为在我们的实际使用中解释器模式使用非常稀少,他只有在做特定公式的解析或者语言解析才会用到,很不幸,目前我的工作中似乎没有可以完整的展示此模式的例子,但是为了加深印象,我们采用《java与模式》中的例子进行说明
此为java与模式中提供的相关例子,主要用于解析条件判断语句,例如:A and B,A or B ,not A等条件语句,表达式分为几类
1、终结符表达式-常量表达式,主要显示true或者false
2、终结符表达式=-变量表达式,主要是需要判断的条件
3、非终结符表达式-各种运算符,包括:与或非
四、场景代码
1、环境(Context)类定义出从变量到布尔值的一个映射
package interpreter.example; import java.util.HashMap; import java.util.Map; public class Context { private Map<Variable,Boolean> map = new HashMap<Variable,Boolean>(); public void assign(Variable var , boolean value){ map.put(var, new Boolean(value)); } public boolean lookup(Variable var) throws IllegalArgumentException{ Boolean value = map.get(var); if(value == null){ throw new IllegalArgumentException(); } return value.booleanValue(); } }
2、定义抽象表达式
package interpreter.example; public abstract class Expression { /** * 以环境为准,本方法解释给定的任何一个表达式 */ public abstract boolean interpret(Context ctx); /** * 检验两个表达式在结构上是否相同 */ public abstract boolean equals(Object obj); /** * 返回表达式的hash code */ public abstract int hashCode(); /** * 将表达式转换成字符串 */ public abstract String toString(); }
3、定义常量表达式
package interpreter.example; public class Constant extends Expression{ private boolean value; public Constant(boolean value){ this.value = value; } @Override public boolean equals(Object obj) { if(obj != null && obj instanceof Constant){ return this.value == ((Constant)obj).value; } return false; } @Override public int hashCode() { return this.toString().hashCode(); } @Override public boolean interpret(Context ctx) { return value; } @Override public String toString() { return new Boolean(value).toString(); } }
4、定义变量表达式
package interpreter.example; public class Variable extends Expression { private String name; public Variable(String name){ this.name = name; } @Override public boolean equals(Object obj) { if(obj != null && obj instanceof Variable) { return this.name.equals( ((Variable)obj).name); } return false; } @Override public int hashCode() { return this.toString().hashCode(); } @Override public String toString() { return name; } @Override public boolean interpret(Context ctx) { return ctx.lookup(this); } }
5、定义逻辑与
package interpreter.example; public class And extends Expression { private Expression left,right; public And(Expression left , Expression right){ this.left = left; this.right = right; } @Override public boolean equals(Object obj) { if(obj != null && obj instanceof And) { return left.equals(((And)obj).left) && right.equals(((And)obj).right); } return false; } @Override public int hashCode() { return this.toString().hashCode(); } @Override public boolean interpret(Context ctx) { return left.interpret(ctx) && right.interpret(ctx); } @Override public String toString() { return "(" + left.toString() + " AND " + right.toString() + ")"; } }
6、定义逻辑或
package interpreter.example; public class Or extends Expression { private Expression left,right; public Or(Expression left , Expression right){ this.left = left; this.right = right; } @Override public boolean equals(Object obj) { if(obj != null && obj instanceof Or) { return this.left.equals(((Or)obj).left) && this.right.equals(((Or)obj).right); } return false; } @Override public int hashCode() { return this.toString().hashCode(); } @Override public boolean interpret(Context ctx) { return left.interpret(ctx) || right.interpret(ctx); } @Override public String toString() { return "(" + left.toString() + " OR " + right.toString() + ")"; } }
7、定义逻辑非
package interpreter.example; public class Not extends Expression { private Expression exp; public Not(Expression exp){ this.exp = exp; } @Override public boolean equals(Object obj) { if(obj != null && obj instanceof Not) { return exp.equals( ((Not)obj).exp); } return false; } @Override public int hashCode() { return this.toString().hashCode(); } @Override public boolean interpret(Context ctx) { return !exp.interpret(ctx); } @Override public String toString() { return "(Not " + exp.toString() + ")"; } }
8、定义客户端代码
package interpreter.example; public class Client { public static void main(String[] args) { Context ctx = new Context(); Variable x = new Variable("x"); Variable y = new Variable("y"); Constant c = new Constant(true); ctx.assign(x, false); ctx.assign(y, true); Expression exp = new Or(new And(c,x) , new And(y,new Not(x))); System.out.println("x=" + x.interpret(ctx)); System.out.println("y=" + y.interpret(ctx)); System.out.println(exp.toString() + "=" + exp.interpret(ctx)); } }
五、总结
解释器模式可以很容易改变和扩展解释方法,但是由于每个文本都需要定义一个类,会导致后期很难管理,因此不太常用。
注:此文代码和案例都是一些经典实现,并无工作体验,以后如果有具体案例再替换