当前位置: 代码迷 >> 综合 >> 设计模式-解释器模式(Interpreter Pattern)
  详细解决方案

设计模式-解释器模式(Interpreter Pattern)

热度:9   发布时间:2023-12-01 20:29:16.0

推荐:Java设计模式汇总

解释器模式

定义

Given a language,define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

类型
行为型。

角色

  • AbstractExpression(抽象表达式):在抽象表达式中声明抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类。
  • TerminalExpression(终结符表达式):终结符表达式是抽象表达式的子类,它实现了与文法中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例。通常在一个解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较为复杂的句子。
  • NonterminalExpression(非终结符表达式):非终结符表达式也是抽象表达式的子类,它实现了文法中非终结符的解释操作,由于在非终结符表达式中可以包含终结符表达式,也可以继续包含非终结符表达式,因此其解释操作一般通过递归的方式来完成。
  • Context(环境类):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通常它临时存储了需要解释的语句。

例子
这里举计算后缀表达式的例子,为了更加简化,这里只处理两种运算符+*,没有括号,并且默认后缀表达式是正确的。

Interpreter接口(抽象表达式)。

package com.kaven.design.pattern.behavioral.interpreter;public interface Interpreter {
    int interpret();
}

NumberInterpreter类(非终结符表达式),实现了Interpreter接口。

package com.kaven.design.pattern.behavioral.interpreter;public class NumberInterpreter implements Interpreter {
    private int number;public NumberInterpreter(int number){
    this.number = number;}public NumberInterpreter(String number){
    this.number = Integer.parseInt(number);}public int interpret() {
    return this.number;}
}

AddInterpreter类(终结符表达式),实现了Interpreter接口。

package com.kaven.design.pattern.behavioral.interpreter;public class AddInterpreter implements Interpreter {
    private Interpreter firstExpression,secondExpression;public AddInterpreter(Interpreter firstExpression, Interpreter secondExpression) {
    this.firstExpression = firstExpression;this.secondExpression = secondExpression;}public int interpret() {
    return this.firstExpression.interpret()+this.secondExpression.interpret();}public String toString(){
    return "+";}
}

MultiInterpreter类(终结符表达式),实现了Interpreter接口。

package com.kaven.design.pattern.behavioral.interpreter;public class MultiInterpreter implements Interpreter {
    private Interpreter firstExpression,secondExpression;public MultiInterpreter(Interpreter firstExpression, Interpreter secondExpression) {
    this.firstExpression = firstExpression;this.secondExpression = secondExpression;}public int interpret() {
    return this.firstExpression.interpret()*this.secondExpression.interpret();}public String toString(){
    return "*";}
}

OperatorUtil类(操作工具类)。

package com.kaven.design.pattern.behavioral.interpreter;public class OperatorUtil {
    public static boolean isOperator(String symbol){
    return (symbol.equals("+") || symbol.equals("*"));}public static Interpreter getExpressionObject(Interpreter firstExpression ,Interpreter secondExpression ,String symbol){
    if(symbol.equals("+")){
    return new AddInterpreter(firstExpression , secondExpression);}else if(symbol.equals("*")){
    return new MultiInterpreter(firstExpression , secondExpression);}return null;}
}

KavenExpressionParser类,这里使用了上面实现的解释器模式相关类和Stack实现了计算后缀表达式的逻辑,计算后缀表达式的算法应该是数据结构的基础吧,这里就不讲了。

package com.kaven.design.pattern.behavioral.interpreter;import java.util.Stack;public class KavenExpressionParser {
    private Stack<Interpreter> stack = new Stack<Interpreter>();public int parse(String str){
    String[] strItemArray = str.split(" ");for(String symbol : strItemArray){
    if(!OperatorUtil.isOperator(symbol)){
    Interpreter numberExpression = new NumberInterpreter(symbol);stack.push(numberExpression);System.out.println(String.format("入栈:%d",numberExpression.interpret()));}else{
    // 是运算符号可以计算Interpreter firstExpression = stack.pop();Interpreter secondExpression = stack.pop();System.out.println(String.format("出栈:%d 和 %d",firstExpression.interpret(),secondExpression.interpret()));Interpreter operator = OperatorUtil.getExpressionObject(firstExpression ,secondExpression , symbol);System.out.println(String.format("应用运算符: %s",operator));int result = operator.interpret();NumberInterpreter resultExpression = new NumberInterpreter(result);stack.push(resultExpression);System.out.println(String.format("阶段结果入栈:%d",resultExpression.interpret()));}}int result  = stack.pop().interpret();return result;}
}

Expression类(环境类),存储后缀表达式。

package com.kaven.design.pattern.behavioral.interpreter;public class Expression {
    private  String expression;public Expression(String expression) {
    this.expression = expression;}public  String getExpression() {
    return this.expression;}
}

应用层代码:

package com.kaven.design.pattern.behavioral.interpreter;public class Test {
    public static void main(String[] args) {
    Expression expression = new Expression("6 100 11 + *");KavenExpressionParser expressionParser = new KavenExpressionParser();int result = expressionParser.parse(expression.getExpression());System.out.println("解释器计算结果"+result);}
}

输出:

入栈:6
入栈:100
入栈:11
出栈:11100
应用运算符: +
阶段结果入栈:111
出栈:1116
应用运算符: *
阶段结果入栈:666
解释器计算结果666

这里便完成了一个简单的解释器模式例子。

适用场景

  • 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
  • 一些重复出现的问题可以用一种简单的语言进行表达。
  • 执行效率不是关键问题。高效的解释器通常不是通过直接解释抽象语法树来实现的,而是需要将它们转换成其他形式,使用解释器模式的执行效率并不高。

优点

  • 易于改变和扩展文法。由于在解释器模式中使用类表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
  • 实现文法较为容易。在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码。

缺点

  • 解释器模式会引起类膨胀。
  • 解释器模式将会导致系统比较复杂, 为维护带来了非常多的麻烦。
  • 执行效率低。由于在解释器模式中一般采用了大量的循环和递归调用(我们的例子是使用栈来代替递归),因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。

如果有说错的地方,请大家不吝赐教(记得留言哦~~~~)。

  相关解决方案