当前位置: 首页 > news >正文

设计模式-解释器模式

设计模式-解释器模式

解释器模式的英文翻译是 Interpreter Design Pattern。它是这样定义的:Interpreter pattern is used to defines a grammatical representation for a language and provides an interpreter to deal with this grammar。翻译成中文就是:解释器模式为某个语言定义它的语法(或者叫文法)表示,并定义一个解释器用来处理这个语法。

简单来说我们可能不懂某些英文的意思,经过翻译解释变成中文,我们就可以理解这个含义了。

从广义上来讲,只要是能承载信息的载体,我们都可以称之为“语言”,比如,古代的结绳记事、盲文、哑语、摩斯密码等。解释器模式主要的组成部分为:语法规则和翻译器,翻译器的作用就是根据语法规则翻译成指定的对象。

案例分析

我定义了一个根据字符串表达式计算数字表达式值的规则,要求传入的字符串是 A+B,例如 “1+2” ,实现一个解释器输出最后的值 3。

public class Main {public static void main(String[] args) {String express = "1+2";String[] split = express.split("\\+");int left = Integer.parseInt(split[0]);int right = Integer.parseInt(split[1]);System.out.println(left + right);}
}

这个案例非常简单,因为我们限制了输入的语法规则,实际上解释器就是这样的思想,传入一个满足所定义语法规则的表达式,解释为最后的对象。

上述的这个案例太简单了,升级一下,传入一个包含基本运算符的后缀表达式,生成最后的结果。

其实这个案例在之前的设计模式中讲过了:设计模式-组合模式,但是它也符合解释器模式的场景,因此这里简化一下实现。

按照规则可以抽象出一个接口

public interface Expression {int getValue();}

接口有五个实现类,分别是 Number、Add、Sub、Multiply 和 Division。其中除了 Number 其他的都需要两个参与者,而且这两个参与者可以是 Expression 的任意实现类。

public class NumberExpression implements Expression{private Integer value;public NumberExpression(Integer value) {this.value = value;}@Overridepublic int getValue() {return value;}}

由于其他的实现类都有两个参与者,因此可以使用抽象类复用创建逻辑

public abstract class BaseExpression implements Expression {protected Expression left;protected Expression right;protected BaseExpression(Expression left, Expression right) {this.left = left;this.right = right;}}
public class AddExpression extends BaseExpression {public AddExpression(Expression left, Expression right) {super(left, right);}@Overridepublic int getValue() {return left.getValue() + right.getValue();}}

省略 Sub、Multiply、Division 等实现

接着我们定义我们的语法规则,由于参数已经是一个合法的后缀表达式了,所以解释步骤如下:

  • 从头到尾遍历每一个字符
    • 如果是数字,转为 NumberExpression 入栈
    • 如果是符号,取出栈顶的两个 Expression 生成符号对应的 Expression 并入栈,例如遇到 + 号,生成一个 AddExpression,左侧表达式为栈的倒数第二个 Expression,右侧表达式为栈的倒数第一个 Expression
  • 遍历完成后,栈中只有一个元素,也就是我们最终生成的 Expression 对象
    public Expression parse() {LinkedList<Expression> stack = new LinkedList<>();for (String item : suffixExpressions) {if (isOperator(item.charAt(0))) {Expression right = stack.removeLast();switch (item) {case "+": {stack.add(new AddExpression(stack.removeLast(), right));break;}case "-": {stack.add(new SubExpression(stack.removeLast(), right));break;}case "*": {stack.add(new MultiplyExpression(stack.removeLast(), right));break;}case "/": {stack.add(new DivisionExpression(stack.removeLast(), right));break;}}} else {stack.addLast(new NumberExpression(Integer.parseInt(item)));}}return stack.getLast();}

假设输入是

List<String> suffixExpressions = Arrays.asList("1", "3", "4", "2", "-", "2", "3", "6","*", "+", "*", "*", "+", "30", "-");

分析一下它的执行逻辑:

  • 遇到 1,封装为 NumberExpression 入栈
  • 遇到 3,封装为 NumberExpression 入栈
  • 遇到 4,封装为 NumberExpression 入栈
  • 遇到 2,封装为 NumberExpression 入栈
  • 遇到 -,取出栈的两个元素,封装为 SubExpression 入栈,此时栈的元素为: 1 3 (4-2)
  • 遇到 2,封装为 NumberExpression 入栈
  • 遇到 3,封装为 NumberExpression 入栈
  • 遇到 6,封装为 NumberExpression 入栈
  • 遇到 *,取出栈的两个元素,封装为 MultiplyExpression 入栈,此时栈的元素为: 1 3 (4-2) 2 (3*****6)
  • 遇到 +,取出栈的两个元素,封装为 AddExpression 入栈,此时栈的元素为: 1 3 (4-2) (2+(3*****6))
  • 遇到 *,取出栈的两个元素,封装为 MultiplyExpression 入栈,此时栈的元素为: 1 3 ((4-2)(2+(36)))
  • 遇到 ,取出栈的两个元素,封装为 MultiplyExpression 入栈,此时栈的元素为: 1 (3****((4-2)(2+(36))))
  • 遇到 +,取出栈的两个元素,封装为 AddExpression 入栈,此时栈的元素为: (1+ (3*****((4-2)(2+(36)))))
  • 遇到 30,封装为 NumberExpression 入栈
  • 遇到 -,取出栈的两个元素,封装为 SubExpression 入栈,此时栈的元素为: ((1+ (3*****((4-2)(2+(36))))) - 30)

验证:

public class Main {public static void main(String[] args) {List<String> suffixExpressions = Arrays.asList("1", "3", "4", "2", "-", "2", "3", "6", "*", "+", "*", "*", "+", "30", "-");ExpressionParse parse = new ExpressionParse();System.out.println(parse.parse(suffixExpressions).getValue());System.out.println(((1 + (3 * ((4 - 2) * (2 + (3 * 6))))) - 30));}}

解释器模式的代码实现比较灵活,没有固定的模板。应用设计模式主要是应对代码的复杂性,解释器模式也不例外。它的代码实现的核心思想,就是将语法解析的工作拆分到各个小类中,以此来避免大而全的解析类。一般的做法是,将语法规则拆分一些小的独立的单元,然后对每个单元进行解析,最终合并为对整个语法规则的解析。

上述的案例就是把后缀表达式解析为5种具体的表达式并进行合并计算,其中其实还用到了组合模式,例如 AddExpression 的左侧和右侧表达式都可以是任何其他表达式,因此使用 Expression 作为参数类型接收,如果左侧的 Expression 也是 AddExpression 或其他高级表达式,展开来看其实是一个多层的树结构,利用 getValue 获得值的时候也是会先计算子节点的值,类似于树的后续遍历。

http://www.dtcms.com/a/470162.html

相关文章:

  • 望牛墩镇仿做网站泰州建设网站
  • 网站建设与网页制作基础入门教程祥云平台官方网站
  • Unreal Engine C++ 开发核心:USceneComponent 常用方法详解
  • 陪诊陪护小程序前端功能解析:就医照料的便捷对接与全流程保障
  • 在线PhotoShop网页版常用快捷键和实用技巧
  • 湖南建设网站公司h5四合一网站建设
  • (一)黑马React(项目初始化/字体和样式/列表循环/高亮排序/自定义hooks/异步RTK)
  • 酒泉网站建设有限公司自己怎样做公司广告视频网站
  • 基于Python的旅游数据可视化系统的分析与设计-计算机毕设 97740
  • PHP MySQL 使用 ORDER BY 排序查询
  • QT中加载PSQL驱动
  • 杭电 神经网络与深度学习 学习笔记
  • 网站建设合优企业做国外网站多少钱
  • 网站建设 主要学是么服装详情页设计
  • 自适应编码调制简介
  • MySQL实战篇05:MySQL主从复制Docker实战(上)——1主2从集群搭建与问题解决
  • 金融网站建设方案ppt模板重庆建设厅官网
  • 从源码优化外卖配送系统:算法调度、智能推荐与数据分析应用
  • 百宝图建设工程电子网站网络公司如何建网站
  • vscode 远程管理docker时,提示权限不足无法获取容器列表问题
  • 定制营销型网站什么意思wordpress建立移动m站
  • 石家庄无极网站建设网站开发实战项目
  • AI智能体(Agent)大模型入门【12】--基于llamaindex框架,fastapi框架实现大模型聊天基于mysql存储的历史对话进行聊天
  • 射频噪声干扰、调频调幅干扰仿真及SAR成像实现
  • 基于 Azure API Management 的企业级 AI 服务网关实现
  • MATLAB绘制9种最新的混沌系统
  • 潍坊网站建设潍坊佛山网站快速排名提升
  • 基于MATLAB的MIT-BIH ECG数据PQRST波定位实现
  • 物联网平台软件知道一个网站怎么知道是谁做的百度优化
  • MATLAB绘制多种混沌系统