真刀实枪之解释器模式

  • 从模型公式说起

    • 需求,输入一个模型公式,然后输入模型中的参数,运算出结果
    • 设计要求
      1. 公式可以运行时编辑
      2. 高扩展性
      3. 效率可以暂不考虑
  • 分析下这个需求,还是比较简单的,就是有一套模板,然后填入参数,计算出相应的结果
    • 这个需求中的角色主要有两个

      1. 运算元素【终结符号:这个元素除了赋值以外,不需要做其他的任何处理】
      2. 运算法则【非终结符号:编写算法进行处理】
  • 运算元素与运算符号的异同点
    • 共同点:都要被解析
    • 不同点:运算元素有相同的功能,可以归为一类;运算符要被分别处理,用不同类来处理
  • 那就从加减模型开始这次的设计之旅吧
    • 加减模型简单类图

    • 看上面这个类图,有什么问题没有?对,运算有先后顺序,加减法可能用不到,但是考虑到扩展性后,乘除加上后就不一样了。好了,问题有了,那么开始解决问题吧!
    • 总的思路有了,现在把细节完善一下吧
  • 设计基本完成,现在动手实现具体的逻辑吧

    • 代码

      • Expression

        package com.peng.js;import java.util.HashMap;/*** @author kungfu~peng* @data 2017年12月3日* @description*/
        public abstract class Expression {public abstract int interpreter(HashMap<String, Integer> var);
        }
        
      • VarExpression

        package com.peng.js;import java.util.HashMap;/*** @author kungfu~peng* @data 2017年12月3日* @description*/
        public class VarExpression extends Expression {private String key;public VarExpression(String key) {super();this.key = key;}// 从map中取值@Overridepublic int interpreter(HashMap<String, Integer> var) {return var.get(key);}}
        
      • SymbolExpression

        package com.peng.js;/*** @author kungfu~peng* @data 2017年12月3日* @description*/
        public abstract class SymbolExpression extends Expression {protected Expression left;protected Expression right;public SymbolExpression(Expression left, Expression right) {super();this.left = left;this.right = right;}}
        
      • AddExpression

        package com.peng.js;import java.util.HashMap;/*** @author kungfu~peng* @data 2017年12月3日* @description*/
        public class AddExpression extends SymbolExpression {public AddExpression(Expression left, Expression right) {super(left, right);}// 把左右两边相加@Overridepublic int interpreter(HashMap<String, Integer> var) {return super.left.interpreter(var) + super.right.interpreter(var);}}
        
      • SubExpression

        package com.peng.js;import java.util.HashMap;/*** @author kungfu~peng* @data 2017年12月3日* @description*/
        public class SubExpression extends SymbolExpression {public SubExpression(Expression left, Expression right) {super(left, right);}// 把左右两边相加@Overridepublic int interpreter(HashMap<String, Integer> var) {return super.left.interpreter(var) - super.right.interpreter(var);}}
        
      • Calculator

        package com.peng.js;import java.util.HashMap;
        import java.util.Stack;/*** @author kungfu~peng* @data 2017年12月3日* @description*/
        public class Calculator {// 定义表达式private Expression expression;// 构造函数传参,并解析public Calculator(String expStr) {super();// 定义一个栈,安排运算的先后顺序Stack<Expression> stack = new Stack<Expression>();// 表达式拆分为字符数组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])));}}}this.expression = stack.pop();}// 开始运算public int run(HashMap<String, Integer> var) {return this.expression.interpreter(var);}}
        
      • Client

        package com.peng.js;import java.io.BufferedReader;
        import java.io.IOException;
        import java.io.InputStreamReader;
        import java.util.HashMap;/*** @author kungfu~peng* @data 2017年12月3日* @description*/
        public class Client {public static void main(String[] args) throws IOException {String expStr = getExpStr();// 赋值HashMap<String, Integer> var = getValue(expStr);Calculator cal = new Calculator(expStr);// 运算结果System.out.println("表达式:" + expStr + "的值=" + cal.run(var));}private static HashMap<String, Integer> getValue(String expStr)throws IOException {HashMap<String, Integer> map = new HashMap<String, Integer>();// 解析有几个参数要传递for (char ch : expStr.toCharArray()) {if (ch != '+' && ch != '-') {// 解决重复参数的问题if (!map.containsKey(String.valueOf(ch))) {System.out.println("请输入" + String.valueOf(ch) + "参数的值:");String in = new BufferedReader(new InputStreamReader(System.in)).readLine();map.put(String.valueOf(ch), Integer.valueOf(in));}}}return map;}// 获得表达式private static String getExpStr() throws IOException {System.out.println("请输入表达式:");return new BufferedReader(new InputStreamReader(System.in)).readLine();}
        }
        
      • 执行结果

        请输入表达式:
        a+b+c
        请输入a参数的值:
        1
        请输入b参数的值:
        2
        请输入c参数的值:
        3
        表达式:a+b+c的值=6
        

解释器模式的定义

  • Interpreter Pattern
  • Given a language,define a representation for its grammer along with an interpret uses the representation to interpretwntences in the language.(给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子)

解释器模式的通用类图

  • 解释
    • AbstractExpression:抽象解释器
    • TerminalExpression:终结符表达式【eg:参数】
    • NonterminalExpression:非终结符表达式【eg:符号】
    • Context:环境角色

通用代码

  • AbstractExpression

    package js2;
    /*** @author kungfu~peng* @data 2017年12月3日* @description*/
    public abstract class Expression {// 解析任务public abstract Object interpreter(Context ctx);
    }
    
  • TerminalExpression

    package js2;/*** @author kungfu~peng* @data 2017年12月3日* @description 终结符表达式*/
    public class TerminalExpression extends Expression {// 通常终结符表达式只有一个,但是有多个对象@Overridepublic Object interpreter(Context ctx) {return null;}}
    
  • NonterminalExpression

    package js2;/*** @author kungfu~peng* @data 2017年12月3日* @description 非终结符表达式*/
    public class NonterminalExpression extends Expression {// 每个非终结符表达式都会对其他表达式产生依赖public NonterminalExpression(Expression... expression) {super();}@Overridepublic Object interpreter(Context ctx) {// 进行文法处理return null;}}
    
  • Context

    package js2;/*** @author kungfu~peng* @data 2017年12月3日* @description */
    public class Context {}
    
  • Client

    package js2;import java.util.Stack;/*** @author kungfu~peng* @data 2017年12月3日* @description*/
    public class Client {public static void main(String[] args) {Context context = new Context();// 通常定义一个语法容器,容纳一个具体的表达式--ListArray,LinkedList,Stack等类型Stack<Expression> stack = null;for (;;) {// 进行语法树判断,并产生递归调用}Expression exp = stack.pop();// 具体元素进入场景exp.interpreter(context);}
    }
    

解释器模式的应用

  • 解释器模式的优点

    1. 语法分析工具
    2. 扩展性好
  • 解释器模式的缺点
    1. 引起类的膨胀
    2. 采用递归--调用复杂
    3. 效率问题【循环和递归引起的】

解释器模式的使用场景

  • 重复发生的问题【服务器日志的处理】
  • 一个简单语法需要解释的场景【简单:减少循环和递归(SQL语法分析)】

解释器模式使用的注意事项

  • 尽量不要在重要的模块使用--维护是个大问题
  • 可以代替解释器模式的技术:shell,JRuby,Groovy等脚本语言

最佳实践

  • 实际开发中使用的非常少:考虑效率、性能、维护等问题
  • 在大中型的框架中可以看到--数据分析、报表设计、科学计算工具
  • 站在巨人的肩膀【开源解析工具包】
    1. Expression4J
    2. MESP
    3. JEP

声明

  • 摘自秦小波《设计模式之禅》第2版;
  • 仅供学习,严禁商业用途;
  • 代码手写,没有经编译器编译,有个别错误,自行根据上下文改正;

设计模式之禅【解释器模式】相关推荐

  1. Java进阶篇设计模式之九----- 解释器模式和迭代器模式

    前言 在上一篇中我们学习了行为型模式的责任链模式(Chain of Responsibility Pattern)和命令模式(Command Pattern).本篇则来学习下行为型模式的两个模式, 解 ...

  2. fcq java_Java设计模式百例 - 解释器模式

    解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式.这种模式实现了一个表达式接口,该接口解释一个特定的上下文. 解释器模式在我们开发过程中并不常用 ...

  3. Java设计模式学习记录-解释器模式

    前言 这次介绍另一个行为模式,解释器模式,都说解释器模式用的少,其实只是我们在日常的开发中用的少,但是一些开源框架中还是能见到它的影子,例如:spring的spEL表达式在解析时就用到了解释器模式,以 ...

  4. 设计模式之略见一斑(解释器模式Interpreter)

    解释器模式是一种比较难理解的模式,但如果你对Command(命令模式)和Composite(组合模式)很了解的话,你会发现其实解释器模式就是这两种的组合.为何要使用解释器模式,如何用解释器模式呢,这就 ...

  5. Net设计模式实例之解释器模式(Interpreter Pattern)

    一.解释器模式简介(Brief Introduction) 解释器模式(Interpreter Pattern),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言 ...

  6. 《研磨设计模式》chap21 解释器模式Interpreter(1)模式介绍

    场景:读写xml文件,如果代码"写死了":谁是谁的child,万一文件父子节点改了,又要改代码. 1. 正常编码(不使用模式) public class ReadAppXml {/ ...

  7. 23种设计模式中的解释器模式

    解释器模式:定义一个语法, 定义一个解释器,该解释器处理该语法句子 将某些复杂问题,表达为某种语法规则,然后构建解释器来解释处理这类句子. 转载于:https://www.cnblogs.com/pi ...

  8. Java描述设计模式(14):解释器模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.解释器模式 1.基础概念 解释器模式是对象的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端 ...

  9. [设计模式-行为型]解释器模式(Interpreter)

    一句话 看起来是用来解释一种语言的文法.(类似不同的解释器子类解释不同的字符) 和编译器类似的解释器, 实际状况可能使用的比较少. 概括 解析 INTERPRETER-俺有一个<泡MM真经> ...

  10. 设计模式之15 - 解释器模式Interpreter

    1. 解释器模式(Interpreter Pattern)的定义 (1)定义 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. ①文法:即语法规则.在解 ...

最新文章

  1. 试题 F: 特别数的和 第十届蓝桥杯
  2. 机器学习笔记:(时间序列中的线性回归)如何选择预测变量
  3. python开机自动运行_python 设置开机启动脚本
  4. 支持javascript的ppt软件_github重磅推荐!一个很好用的PPT生成工具
  5. java运行效率优化_如何优化JAVA代码及提高执行效率
  6. php数组实例,php常用数组函数实例小结
  7. Python使用pyexecjs代码案例解析
  8. 高质量C++编程指南
  9. 2018年湘潭大学程序设计竞赛 F maze
  10. MAC电脑Command键怎么调换为Control键
  11. 智能电动汽车充电桩去除安全隐患提高充电效率
  12. win10+ubuntu16.04双系统下完全删除并重装ubuntu16.04
  13. Excel做文件归档
  14. 检查计算机设备报告书,关于计算机安全检查的自查报告范文
  15. Dubbo的failsafe容错策略
  16. Google 工程师亲授:菜鸟开发者一定要投资的十大目标
  17. 如何用god.html文件刷步,微信运动步数无限修改教程最高98800
  18. 基于YOLOV5的自动瞄准(附代码)
  19. DirectoryInfo 类
  20. win7 计算机名称 ip6,Win7系统提示ipv6无网络访问权限的两种原因及解决方法

热门文章

  1. MAC恢复出厂设置(官方教程)
  2. 算法作业04(回溯与分支界限算法)(骑士游历与行列变换问题)
  3. 计算机程序ppt,计算机和计算机程序.ppt
  4. 好用的Web前端开发框架有哪些呢?推荐这9款
  5. 机器学习必看书籍推荐
  6. c-lightning 闪电网络配置洋葱服务(tor)
  7. Excel 中根据一列查询其他列中的值
  8. webpy使用说明(一)
  9. vue前端怎么下载后端返回的二进制流excel表格文件
  10. 自然风景Mac高清动态壁纸分享来了