标准 专业
多元 极客

设计模式实验室(13)——解释器模式

什么是解释器模式

解释器模式是一种类行为型模式

解释器模式用于定义一个文法,通过解释器来解释为其中的代码。

解释器模式在开发中用的不多,通常应用于研发过程中。

比如说,我们优化出了一个精妙绝伦的文法,但是这个算法对于开发者来说很难应用,所以我们就需要将开发者的语句解释成文法。

 

核心结构

  • Context。环境类,用于存储解释器之外的全局信息,通常用于存储需要解释的语句。
  • AbstractExpression。抽象表达式,声明了解释方法。
  • TerminalExpression。终结符表达式,是抽象表达式的子类,它实现了终结符相关联的解释方法,文法语句中每个终结符都是该类的子类,可以通过非终结符表达式组合成复杂的句子。
  • NonterminalExpression。非终结符表达式,它同样实现了抽象表达式的解释方法,既可以继续包含终结符表达式,也可以包含非终结符表达式,因此解释方法一般通过简单算法、循环、递归方式完成。

类图展示

解释器模式

代码分析

解释器模式在我们的开发中不经常用到,但是在研发中,是非常常见的设计模式,比如说当我们需要设计一个计算器时,就需要把输入的实数解释成机器可以读懂的语言。

那我们就实现一个简单的计算器吧。

首先,创建环境类,告诉文法,我们要做什么:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
 * 解释器模式——环境类
 */
public class Context {

    private Map<String, Integer> values = new HashMap<String, Integer>();  

    public void put(String key, Integer value) {
        values.put(key, value);
    }   

    public Integer get(String key) {
        if (values.containsKey(key)) {
            return values.get(key);
        }
        return 0;
    }
}

Context中,我们用一个HashMap来存储参数和对应的值。

接下来我们就应该创建核心类——抽象表达式:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
 * 解释器模式——抽象表达式
 */
public abstract class Expression {  

    public abstract int interpreter(Context context);
}

根据前面的类图我们可知,表达式又分为终结表达式和非中介表达式。

所以我们先创建一个基本的——终结表达式:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
 * 解释器模式——终结表达式
 */
public class ValueExpression extends Expression{

    private Integer i;

    public Integer getI() {
        return i;
    }

    public void setI(Integer i) {
        this.i = i;
    }

    public ValueExpression(Integer i) {
        this.i = i;
    }

    @Override
    public int interpreter(Context context) {
        return this.i;
    }
}

而在本次实例中,非终结表达式代表加、减、乘、除的运算。

首先我们本着抽象继承的思维,创建一个抽象父类——操作符表达式:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
 * 解释器模式——抽象非终结表达式
 */
public abstract class OperationExpression extends Expression {

    protected Expression left;

    protected Expression right;

    public OperationExpression() {

    }

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

接下来创建加、减、乘、除四个具体操作符表达式。

加法:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
 * 解释器模式——非终结具体表达式
 */
public class AddOperationExpression extends OperationExpression {

    public AddOperationExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(Context context) {
        return this.left.interpreter(context) + this.right.interpreter(context);
    }
}

减法:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
 * 解释器模式——非终结具体表达式
 */
public class MinusOperationExpression extends OperationExpression {

    public MinusOperationExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(Context context) {
        return this.left.interpreter(context) - this.right.interpreter(context);
    }
}

乘法:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
 * 解释器模式——非终结具体表达式
 */
public class MultiplyOperationExpression extends OperationExpression {

    public MultiplyOperationExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(Context context) {
        return this.left.interpreter(context) * this.right.interpreter(context);
    }
}

除法:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
 * 解释器模式——非终结具体表达式
 */
public class DivideOperationExpression extends OperationExpression {

    public DivideOperationExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(Context context) {
        return this.left.interpreter(context) / this.right.interpreter(context);
    }
}

惯例,测试代码:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
 * 解释器模式测试
 */
public class InterpreterTest {

    public static void main(String[] args) {
        Context context = new Context();
        context.put("a", 9);
        context.put("b", 8);
        context.put("c", 7);
        context.put("d", 6);
        context.put("e", 5);

        // (9 + 8 - 7) * 6 / 5
        Expression addOperationExpression = new AddOperationExpression(new ValueExpression(context.get("a")), new ValueExpression(context.get("b")));
        Expression minusOperationExpression = new MinusOperationExpression(addOperationExpression, new ValueExpression(context.get("c")));
        Expression multiplyOperationExpression = new MultiplyOperationExpression(minusOperationExpression, new ValueExpression(context.get("d")));
        Expression divideOperationExpression = new DivideOperationExpression(multiplyOperationExpression, new ValueExpression(context.get("e")));
        System.out.println(divideOperationExpression.interpreter(context));
    }
}

模式总结

优点

  • 易于改变和扩展文法,可以通过对抽象表达式的多种实现,创造更多的解释语法。
  • 每一条文法规则代表一个类,可以方便地实现一个简单的语言。
  • 符合开闭原则,复杂语法表达式可以通过添加、组合终结表达式和非终结表达式即可,无需变更已有具体表达式。
  • 每个表达式都是类似的,可以利用工具批量生产。

缺点

  • 对于复杂的文法,可能有较大的设计难度,同时可能会造成类的指数级别增长。
  • 由于会使用大量的循环和递归调用,生成的算法的时间复杂度可能不尽如人意。

适用场景

  • 核心文法,通过解释器模式方便开发者使用。
  • 简单的文法。
  • 忽略执行效率的文法。
  • 重复出现的问题,酌情使用解释器模式进行解决。
赞(0) 投币

评论 抢沙发

慕勋的实验室慕勋的研究院

码字不容易,路过请投币

支付宝扫一扫

微信扫一扫