解释器模式
解释器模式:给定一个语言,定义他的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器模式需要解决的是:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
用了解释器,就意味着很容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可以使用继承来改变或扩展该文法。也比较容易实现文法。因为定义抽象语法树种各个节点的类的实现大体类似,这些类都抑郁直接编写。
解释器模式也有不足之处:解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其他的技术如语法分析程序或编译器生成器来处理。
UML图:
1 //AbstractExpression抽象表达式,声明一个抽象的解释操作,这个接口为抽象语法树种所有的节点所共享 2 public abstract class AbstractExpression { 3 public abstract void interpret(Context context); 4 }
1 /** 2 * NonterminalExpression非终结符表达式,为文法中的非终结符实现解释器操作。 3 * 对文法中每一条规则R1、R2....Rn都需要一个具体的终结符表达式类。通过实现抽象表达式的interpret()方法实现解释操作。 4 * 解释操作以递归方式调用上面所提到的代表R1、R2...Rn中各个符号的实例变量。 5 * @author 贤元 6 * 7 */ 8 public class NonterminalExpression extends AbstractExpression { 9 10 @Override 11 public void interpret(Context context) { 12 System.out.println("非终端解释器"); 13 } 14 15 }
1 /** 2 * TerminalExpression终结符表达式,实现与文中的终结符相关联的解释操作。 3 * 实现抽象表达式中所要求的接口,主要是一个interpret()方法。 4 * 文法中每一个终结符都有一个具体终结符表达式与之相对应 5 * @author 贤元 6 * 7 */ 8 public class TerminalExpression extends AbstractExpression{ 9 10 @Override 11 public void interpret(Context context) { 12 System.out.println("终端解释器"); 13 } 14 15 }
1 //Context包含解释器之外的一些全局信息 2 public class Context { 3 private String input; 4 private String output; 5 public String getInput() { 6 return input; 7 } 8 public void setInput(String input) { 9 this.input = input; 10 } 11 public String getOutput() { 12 return output; 13 } 14 public void setOutput(String output) { 15 this.output = output; 16 } 17 18 }
1 //客户端代码,构建表示该文法定义的语言中的一个特定的句子的抽象语法树。调用解释操作 2 public class TestClient { 3 public static void main(String[] args) { 4 Context context =new Context(); 5 List<AbstractExpression> list = new ArrayList<AbstractExpression>(); 6 list.add(new TerminalExpression()); 7 list.add(new NonterminalExpression()); 8 list.add(new TerminalExpression()); 9 list.add(new TerminalExpression()); 10 11 for(AbstractExpression exp:list){ 12 exp.interpret(context); 13 } 14 15 /** 16 * 打印结果: 17 * 终端解释器 18 非终端解释器 19 终端解释器 20 终端解释器 21 */ 22 } 23 }
不能只满足于写完代码运行结果正确就完事,时常考虑如何让代码更加简练更加容易维护、容易扩展和复用,只有这样才可以真正得到提高
--《来自大话设计模式》