解释器模式——java设计模式(十七)

简介

解释器模式(Interpreter Pattern):给定一个语言,定义文法的一种表示,并定义一个解释器,使用该表示解释语言中的句子。

  • 为了更好的描述特定的问题,可以创建新的语言,拥有自己的表达式和结构,即文法规则。可使用解释器模式设计语言。
  • 文法规则:符号“::=”表示“定义为”,“|”表示或,“{”和“}”表示组合,“*”表示出现0次或多次。其中使用频率最高的符号是表示“或”关系的“|”,如文法规则“boolValue ::= 0 | 1”表示终结符表达式boolValue的取值可以为0或者1。
expression ::= value | operation
operation ::= expression '+' expression | expression '-'  expression
value ::= an integer //一个整数值
  • 抽象语法树:可以通过终结符表达式value和非终结符表达式operation组成复杂的语句。每个文法规则的语言实例都可以表示为一个抽象语法树。

结构和实现

  • 角色包括:
    • 抽象表达式:声明抽象解释操作,是所有终结符表达式、非终结符表达式的父类。
    • 终结符表达式:句子中的每一个终结符都是该类的一个实例。
    • 非终结符表达式:对应句子中的非终结符,可通过递归实现操作。
    • 环境类:除解释器之外的全局信息,通常临时存储需要解释的语句,或者解释器共有的功能。
  • 解释器的结构。
    180513.interpret.png

实例

  • 开发机器人控制程序,通过英文控制,每个表达式包括移动方向、方式、距离,表达式之间通过and连接,例如: down run 10 and left move 20。
  • 抽象语法树。
  • 控制程序结构。
    180513.robot.png
  • 指令处理类,将语句解析成结点树。
public class InstructionHandler {  
    private AbstractNode node;  

    public void handle(String instruction) {  
        AbstractNode left = null, right = null;  
        AbstractNode direction = null, action = null, distance = null;  
        Stack stack = new Stack(); //声明一个栈对象用于存储抽象语法树  
        String[] words = instruction.split(" "); //以空格分隔指令字符串  
        for (int i = 0; i < words.length; i++) {  
//本实例采用栈的方式来处理指令,如果遇到“and”,则将其后的三个单词作为三个终结符表达式连成一个简单句子SentenceNode作为“and”的右表达式,而将从栈顶弹出的表达式作为“and”的左表达式,最后将新的“and”表达式压入栈中。                   if (words[i].equalsIgnoreCase("and")) {  
                left = (AbstractNode)stack.pop(); //弹出栈顶表达式作为左表达式  
                String word1= words[++i];  
                direction = new DirectionNode(word1);  
                String word2 = words[++i];  
                action = new ActionNode(word2);  
                String word3 = words[++i];  
                distance = new DistanceNode(word3);  
                right = new SentenceNode(direction,action,distance); //右表达式  
                stack.push(new AndNode(left,right)); //将新表达式压入栈中  
            }  
            //如果是从头开始进行解释,则将前三个单词组成一个简单句子SentenceNode并将该句子压入栈中  
            else {  
                String word1 = words[i];  
                direction = new DirectionNode(word1);  
                String word2 = words[++i];  
                action = new ActionNode(word2);  
                String word3 = words[++i];  
                distance = new DistanceNode(word3);  
                left = new SentenceNode(direction,action,distance);  
                stack.push(left); //将新表达式压入栈中  
            }  
        }  
        this.node = (AbstractNode)stack.pop(); //将全部表达式从栈中弹出  
    }  

    public String output() {  
        String result = node.interpret(); //解释表达式  
        return result;  
    }  
}  

优缺点和适用范围

  • 优点:
    • 易于修改文法。通过类表示文法,可以使用继承扩展和改变,符合开闭原则。
    • 方便实现。每条文法规则可以表示未一个类,方法实现一个简单语言。
  • 缺点:
    • 复杂文法难维护。每一条规则需要定义一个类,文法太多,则导致类难以管理和维护,可以考虑使用语法分析程序代替。
    • 执行效率低。使用大量循环和递归,效率低,调试困难。
  • 适用范围:
    • 需要将语句表示为抽象语法树。
    • 重复出现的问题可用简单语言表示。
    • 执行效率影响不大。

jdk中的应用

  • java.util.Pattern类,通过compile方法编译正则表达式这一种语言,并与字符串匹配。
  • Pattern详解

猜你喜欢

转载自blog.csdn.net/qq_40369829/article/details/80370585