二十一、解释器模式——解析表达式和脚本
文章目录
- 解释器模式
-
- 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+c1235运算结果:a+b+c=20
总结
解释器模式代码实现的核心思想,就是将语法解析的工作拆分到各个小类中,以此来避免大而全的解析类。一般的做法是,将语法规则拆分成一些小的独立的单元,然后对每个单元进行解析,最终合并为对整个语法规则的解析。
设计模式系列在github上有一个开源项目,主要是本系列博客的demo代码。https://github.com/forestnlp/designpattern
如果您对软件开发、机器学习、深度学习有兴趣请关注本博客,将持续推出Java、软件架构、深度学习相关专栏。
您的支持是对我最大的鼓励。
《新程序员》:云原生和全面数字化实践
50位技术专家共同创作,文字、视频、音频交互阅读