设计模式——解释器模式

558 阅读4分钟

1. 解释器模式概述

解释器模式提供了评估语言的语法或表达式的方式。
这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在SQL解析、符号处理引擎等。

(1) 适用情况

如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

这句话有点晦涩,我自己的理解是,如果一类问题可以分为比较固定的一些语句或者计算的话,那么可以把这些语句或计算封装为一个个类,然后用这些类所表示的子问题组成原问题。通过对各个子问题进行计算,从而得到原问题的结果。

(2) 优点

可拓展性好,灵活。

(3) 缺点

复杂,理解较为困难,不便维护,使用场景较少。

2. 解释器模式实例

这里使用解释器模式,来实现简单的计算器。

(1) 实现上下文类

public class Context {
    private Map<Expression, Integer> map = new HashMap<>();

    /**
     * 增加上下文信息
     */
    public void add(Expression expression, int value) {
        map.put(expression, value);
    }

    /**
     * 根据上下文信息,将表达式解析为数字
     */
    public int convert(Expression expression) {
        return map.get(expression);
    }
}

(2) 声明表达式接口

public interface Expression {
    int interpret(Context context);
}

(3) 实现字符表达式类,表示变量

public class CharacterExpression implements Expression {
    String variable;

    public CharacterExpression(String variable) {
        this.variable = variable;
    }

    @Override
    public int interpret(Context context) {
        return context.convert(this);
    }
}

(4) 实现数字表达式类,表示常量

public class IntegerExpression implements Expression {
    int value;

    public IntegerExpression(int value) {
        this.value = value;
    }

    @Override
    public int interpret(Context context) {
        return value;
    }
}

(5) 实现操作符表达式,表示运算

public abstract class OperatorExpression implements Expression {
    /**
     * 操作符需要两个表达式
     */
    Expression expression1;
    Expression expression2;

    public OperatorExpression(Expression expression1, Expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }
}

(6) 实现加减乘除表达式

public class PlusExpression extends OperatorExpression {

    public PlusExpression(Expression expression1, Expression expression2) {
        super(expression1, expression2);
    }

    @Override
    public int interpret(Context context) {
        int value1 = this.expression1.interpret(context);
        int value2 = this.expression2.interpret(context);
        return value1 + value2;
    }
}
public class MinusExpression extends OperatorExpression {

    public MinusExpression(Expression expression1, Expression expression2) {
        super(expression1, expression2);
    }

    @Override
    public int interpret(Context context) {
        int value1 = this.expression1.interpret(context);
        int value2 = this.expression2.interpret(context);
        return value1 - value2;
    }
}
public class MultiExpression extends OperatorExpression {

    public MultiExpression(Expression expression1, Expression expression2) {
        super(expression1, expression2);
    }

    @Override
    public int interpret(Context context) {
        int value1 = this.expression1.interpret(context);
        int value2 = this.expression2.interpret(context);
        return value1 * value2;
    }
}
public class DivisionExpression extends OperatorExpression {

    public DivisionExpression(Expression expression1, Expression expression2) {
        super(expression1, expression2);
    }

    @Override
    public int interpret(Context context) {
        int value1 = this.expression1.interpret(context);
        int value2 = this.expression2.interpret(context);
        return value1 / value2;
    }
}

(7) 实现幂运算表达式

public abstract class PowExpression implements Expression {
    /**
     * 幂运算只需要一个表达式
     */
    Expression expression;

    public PowExpression(Expression expression) {
        this.expression = expression;
    }
}

(8) 实现平方和立方表达式

public class Pow2Expression extends PowExpression {
    public Pow2Expression(Expression expression) {
        super(expression);
    }

    /**
     * 计算平方
     */
    @Override
    public int interpret(Context context) {
        int value = this.expression.interpret(context);
        return value * value;
    }
}
public class Pow3Expression extends PowExpression {
    public Pow3Expression(Expression expression) {
        super(expression);
    }

    /**
     * 计算立方
     */
    @Override
    public int interpret(Context context) {
        int value = this.expression.interpret(context);
        return value * value * value;
    }
}

(9) 进行计算

public class InterpreterDemo {
    public static void main(String[] args) {
        // 题目:计算(x^3 + (y^2 - z * 2)) / 2等于多少
        // 其中x = 3, y = 3, z = 1

        // 构造x,y,z变量和数字2
        CharacterExpression x = new CharacterExpression("x");
        CharacterExpression y = new CharacterExpression("y");
        CharacterExpression z = new CharacterExpression("z");
        IntegerExpression num2 = new IntegerExpression(2);

        // 构造y^2
        Pow2Expression pow2Expression = new Pow2Expression(y);

        // 构造z * 2
        MultiExpression multiExpression = new MultiExpression(z, num2);

        // 构造(y^2 - z * 2)
        MinusExpression minusExpression = new MinusExpression(pow2Expression, multiExpression);

        // 构造x^3
        Pow3Expression pow3Expression = new Pow3Expression(x);

        // 构造(x^3 + (y^2 - z * 2))
        PlusExpression plusExpression = new PlusExpression(pow3Expression, minusExpression);

        // 构造(x^3 + (y^2 - z * 2)) / 2
        DivisionExpression divisionExpression = new DivisionExpression(plusExpression, num2);

        // 给上下文赋值
        Context context = new Context();
        // x = 3
        context.add(x, 3);
        // y = 3
        context.add(y, 3);
        // z = 1
        context.add(z, 1);
        // 计算结果
        System.out.println(divisionExpression.interpret(context));
    }
}

运算结果:
image.png

3. 一些思考

解释器模式算是最复杂的一类设计模式了。

Express接口中有一个方法interpret,入参Context为上下文,表示根据上下文进行解释。
每个Expression的实现类都需要实现该方法,来表明如何进行根据上下文进行解释。

CharacterExpression表示变量,比如题目中的x、y、z;
IntegerExpression表示常量,比如题目中的2。
它们都实现了Expression接口。

OperatorExpression和PowExpression分别表示操作符运算和幂运算。
它们也都实现了Expression接口。

Context表示上下文,也就是题目中变量所对应的值。
其中有两个方法,add方法用来增加上下文信息,convert方法用来将变量解析为数字常量。

参考引用

解释器模式:www.runoob.com/design-patt…
解释器模式:blog.csdn.net/niunai112/a…