Java设计模式之 [19] 行为型模式 - 解释器模式

简介

1.在编译原理中,一个算数表达式通常是词法分析器形成词法单元,而后这些词法单元在通过 语法分析器 构建语法分析树,最终形成一个抽象的语法分析树.这里的词法分析器和语法分析器都可以看成是解释器
2.解释器模式(Interpreter Pattern):是指定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式)
3.应用场景

  • 应用可以将一个需要执行的语言中的句子表示为一个抽象语法树.
  • 一些重复出现的问题可以用一种简单的语言来表达
  • 一个简单的语法需要解释的场景
    4.这样的例子还有:比如编译器.运算表达式,正则表达式,机器人等
原理类图与角色分析

1.类图


Java设计模式之 [19] 行为型模式 - 解释器模式_第1张图片
类图

2.角色分析
Context:是环境角色,含有解释器之外的全局信息
AbstractExpression:抽象表达式,声明一个抽象的解释操作,这个方法为抽象语法树中所有节点共享
TerminalExpression: 为终结者表达式.实现与文法中的终结符相关的解释操作
NoTerminalExpression : 为非终结者表达式,为文法中的非终结符实现的解释操作
说明:输入Context 和 TerminalExpression信息通过Cilent 输入即可

案例分析 四则运算问题

通过解释器模式来实现四则运算,如计算 a+b-c 的值 具体要求
1.先输入表达式的形式 比如 a+b+c-d-e 要求表达式的字母不能重复,
2,分别输入 a,b,c,d,e 的值
3.然后计算出结果


Java设计模式之 [19] 行为型模式 - 解释器模式_第2张图片
计算结果
问题分析

1.编写一个方法,接收表达式的形式,然后根据用户输入的数值进行解析计算,得到结果
2.问题分析:如果输入新的运算符.比如 / * 等等 不利于拓展 另外一个方法来解析会造成程序结构混乱
3.解决方案:可以考虑使用解释器模式 即 : 表达式 ==>> 解释器 (可以有多种) ==>> 结果

解释器模式实现四则运算

1.思路和图解分析


Java设计模式之 [19] 行为型模式 - 解释器模式_第3张图片
类图

2.代码实现

public class AddExpression extends SymbolExpression  {

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

    public int interpreter(HashMap var) {
        return super.left.interpreter(var) + super.right.interpreter(var);
    }
}
public class Calculator {

    // 定义表达式
    private Expression expression;

    // 构造函数传参,并解析
    public Calculator(String expStr) {
        // 安排运算先后顺序
        Stack stack = new Stack<>();
        char[] charArray = expStr.toCharArray();

        Expression left = null;
        Expression right = null;
        for (int i = 0; i < charArray.length; i++) {
            switch (charArray[i]) {
            case '+': //
                left = stack.pop();//
                right = new VarExpression(String.valueOf(charArray[++i]));//
                stack.push(new AddExpression(left, right));//
                break;
            case '-': // 
                left = stack.pop();
                right = new VarExpression(String.valueOf(charArray[++i]));
                stack.push(new SubExpression(left, right));
                break;
            default: 
                stack.push(new VarExpression(String.valueOf(charArray[i])));
                break;
            }
        }
        this.expression = stack.pop();
    }

    public int run(HashMap var) {
        return this.expression.interpreter(var);
    }
}
public abstract class Expression {

    public abstract int interpreter(HashMap var);
}
public class SubExpression extends SymbolExpression {

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

    public int interpreter(HashMap var) {
        return super.left.interpreter(var) - super.right.interpreter(var);
    }
}
/**
 * 抽象运算符号解析器 这里,每个运算符合都只和自己左右两个数字有关系,
 * 但左右两个数字有可能也是一个解析的结果,无论何种类型,都是Expression类的实现类
 * 
 * @author Administrator
 *
 */
public class SymbolExpression extends Expression {

    protected Expression left;
    protected Expression right;

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

    @Override
    public int interpreter(HashMap var) {
        // TODO Auto-generated method stub
        return 0;
    }
}
public class VarExpression extends Expression {

    private String key; 

    public VarExpression(String key) {
        this.key = key;
    }

    @Override
    public int interpreter(HashMap var) {
        return var.get(this.key);
    }
}

测试

public class ClientTest {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        String expStr = getExpStr(); 
        HashMap var = getValue(expStr);
        Calculator calculator = new Calculator(expStr);
        System.out.println("运算结果:" + expStr + "=" + calculator.run(var));
    }

    // 获得表达式
    public static String getExpStr() throws IOException {
        System.out.print("请输入表达式:");
        return (new BufferedReader(new InputStreamReader(System.in))).readLine();
    }

    // 获得值映射
    public static HashMap getValue(String expStr) throws IOException {
        HashMap map = new HashMap<>();

        for (char ch : expStr.toCharArray()) {
            if (ch != '+' && ch != '-') {
                if (!map.containsKey(String.valueOf(ch))) {
                    System.out.print("请输入" + String.valueOf(ch) + "的值:");
                    String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
                    map.put(String.valueOf(ch), Integer.valueOf(in));
                }
            }
        }

        return map;
    }
}

测试结果

请输入表达式:a+b+c-d-e
请输入a的值:10
请输入b的值:50
请输入c的值:12
请输入d的值:78
请输入e的值:20
运算结果:a+b+c-d-e=-26
解释器设计模式在Spring框架应用的源码分析

1.Spring框架中,SpelExpressionParser 就使用到解释器模式

import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class Interpreter {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //创建一个 Parser 对象
        SpelExpressionParser parser = new SpelExpressionParser();
        //
        //通过 Parser 对象 获取到一个Expression对象
        //会根据不同的  Parser 对象 ,返回不同的 Expression对象
        Expression expression = parser.parseExpression("10 * (2 + 1) * 1 + 66"); //96
        int result = (Integer) expression.getValue();
        System.out.println(result);

    }

}
解释器模式的注意事项和细节

1.当有一个语言需要解释执行.可将该语言中的句子表示为一个抽象语法树,就可以考虑使用编译器模式,让程序具有良好的拓展性
2.应用场景:编译器,运算表达式计算.正则表达式,机器人等
3.使用解释器可能带来的问题:解释器模式会引起类膨胀,解释器模式采用递归调用方法,将会导致调试程序非常复杂,效率可能降低

你可能感兴趣的:(Java设计模式之 [19] 行为型模式 - 解释器模式)