二十一、解释器模式——解析表达式和脚本

文章目录

  • 解释器模式
    • 1.Expression
    • 2.Caculator
    • 3.Main
  • 总结

设计模式是面向问题、场景而总结产生的设计思路。是解决问题的套路。23 种经典的设计模式。它们又可以分为三大类:创建型、结构型、行为型。

行为型 包含了 观察者模式、模板模式、策略模式、职责链模式、状态模式、迭代器模式、 访问者模式、备忘录模式、命令模式、解释器模式、中介模式 总共11种模式。

解释器模式

给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语句中的表达式。

  • 抽象表达式角色(Expression):声明一个所有的具体表达式角色都需要实现的抽象接口。这个接口主要是一个interpret()方法,称作解释操作。
  • 终结符表达式角色(Terminal Expression):实现了抽象表达式角色所要求的接口,主要是一个interpret()方法;文法中的每一个终结符都有一个具体终结表达式与之相对应。
  • 非终结表达式角色(Nonterminal Expression):文法中的每一条规则都需要一个具体的非终结符表达式。比如公式R=R1+R2中,+就是非终结符,解析+的解释器就是一个非终结符表达式
  • 环境角色(Context):这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,很多情况下我们使用Map来充当环境角色就够了。

1.Expression

定义表达式,有2中子类,一类是变量型,从map中就可以取值了。一类是符号型,这里支持加减。

public abstract class Expression {
    public abstract int interpreter(HashMap<String,Integer> var);
}

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<String, Integer> var) {
        return 0;
    }
}

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

    @Override
    public int interpreter(HashMap<String, Integer> map) {
        return super.left.interpreter(map) + super.right.interpreter(map);
    }
}

public class MinusExpression extends SymbolExpression{
    public MinusExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(HashMap<String, Integer> map) {
        return super.left.interpreter(map) - super.right.interpreter(map);
    }
}

2.Caculator

Caculator 将字符串解析为表达式。其方法是将字符组合成一个复杂的表达式对象,每个对象的left和right都是表达式。

public class Calculator {
    public Expression parse(String expStr) { // expStr = a+b
        Stack<Expression> stack = new Stack<>();

        char[] charArray = expStr.toCharArray();// [a, +, b]

        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 MinusExpression(left, right));
                    break;
                default:
                    stack.push(new VarExpression(String.valueOf(charArray[i])));
                    break;
            }
        }
        return stack.pop();
    }
}

3.Main

public class Main {
    public static void main(String[] args) throws IOException {
        String expStr = new BufferedReader(new InputStreamReader(System.in)).readLine();
        HashMap<String,Integer> map = new HashMap<>();
        for(char c:expStr.toCharArray()) {
            if(c!='+'&&c!='-'&&!map.containsKey(String.valueOf(c))){
                String val = new BufferedReader(new InputStreamReader(System.in)).readLine();
                map.put(String.valueOf(c),Integer.valueOf(val));
            }
        }
        Calculator calculator = new Calculator();
        Expression expression = calculator.parse(expStr);
        System.out.println("运算结果:" + expStr + "=" + expression.interpreter(map));
    }
}

运行结果:

a+b+c
12
3
5
运算结果:a+b+c=20

总结

解释器模式代码实现的核心思想,就是将语法解析的工作拆分到各个小类中,以此来避免大而全的解析类。一般的做法是,将语法规则拆分成一些小的独立的单元,然后对每个单元进行解析,最终合并为对整个语法规则的解析。

设计模式系列在github上有一个开源项目,主要是本系列博客的demo代码。https://github.com/forestnlp/designpattern
如果您对软件开发、机器学习、深度学习有兴趣请关注本博客,将持续推出Java、软件架构、深度学习相关专栏。
您的支持是对我最大的鼓励。

你可能感兴趣的:(设计模式,java,设计模式,开发语言,后端,架构)