设计模式-解释器模式

news/2024/9/24 1:16:41

解释器模式(InterPreter Pattern)

解释器模式是指给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用 该表示 来解释语言中的句子,并按照规定的语法进行解析的模式,属于行为型模式。

比如编译器可以将源码编译为机器码,让CPU能进行识别并运行。解释器模式的作用其实与编译器一样,都是对固定的文法进行解释,构建出一个解释句子的解释器。

解释器模式实际开发中使用较少,一般源码中会使用,比如Spring的el表达式,以及jdk对正则的支持等

适用场景

  • 一些重复出现的问题可以用一种简单的语言来进行表达
  • 一个简单语法需要解释的场景

角色

  • 抽象表达式Expression:负责定义一个解释方法interpret,交由具体子类进行具体解释
  • 终结符表达式TerminalExpression:实现文法中与终结符有关的操作。文法中的每一个终结符都有一个具体终结表达式与之相呼应。比如R=R1+R2,R1与R2就是终结符,对应的 解析R1和R2的解释器 就是终结符表达式。通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符(R1,R2)。
  • 非终结符表达式NonTerminalExpression:实现文法中与非终结符有关的解释操作。文法中的每条规则都对应于一个非终结符表达式。非终结表达式一般是文法中的运算符或者其他关键字。
  • 上下文环境类Context:包含解释器之外的全局信息。他的任务一般是用来存放文法中各个终结符所对应的具体值。

代码示例

用解释器模式实现一个数学表达式计算器

  • 抽象表达式角色:
package com.caozz.demo2.interpreter.calculate;public interface IArithmeticInterpreter {int interpret();
}
  • 非终结表达式角色抽象
package com.caozz.demo2.interpreter.calculate;public abstract class SymbolInterpreter implements IArithmeticInterpreter {protected IArithmeticInterpreter left;protected IArithmeticInterpreter right;public SymbolInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {this.left = left;this.right = right;}
}
  • 具体非终结表达式(加减乘除)
package com.caozz.demo2.interpreter.calculate;public class AddInterpreter extends SymbolInterpreter {public AddInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {super(left, right);}public int interpret() {return this.left.interpret() + this.right.interpret();}
}
package com.caozz.demo2.interpreter.calculate;public class SubInterpreter extends SymbolInterpreter {public SubInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {super(left, right);}public int interpret() {return this.left.interpret() - this.right.interpret();}
}
package com.caozz.demo2.interpreter.calculate;public class MultiInterpreter extends SymbolInterpreter {public MultiInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right){super(left,right);}public int interpret() {return this.left.interpret() * this.right.interpret();}}
package com.caozz.demo2.interpreter.calculate;public class DivInterpreter extends SymbolInterpreter {public DivInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right){super(left,right);}public int interpret() {return this.left.interpret() / this.right.interpret();}}
  • 终结符表达式(数字表达式)
package com.caozz.demo2.interpreter.calculate;public class NumInterpreter implements IArithmeticInterpreter {private int value;public NumInterpreter(int value) {this.value = value;}public int interpret() {return this.value;}
}
  • 计算器
    parse方法对应的是不考虑优先级的,parse01是考虑优先级的
package com.caozz.demo2.interpreter.calculate;import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;public class GPCalculator {private Stack<IArithmeticInterpreter> stack = new Stack<>();Queue<IArithmeticInterpreter> finalNum = new LinkedList<>();public GPCalculator(String expression) {
//        this.parse(expression);this.parse01(expression);}private void parse(String expression) {String [] elements = expression.split(" ");IArithmeticInterpreter leftExpr, rightExpr;for (int i = 0; i < elements.length ; i++) {String operator = elements[i];if (OperatorUtil.isOperator(operator)){leftExpr = this.stack.pop();rightExpr = new NumInterpreter(Integer.valueOf(elements[++i]));System.out.println("出栈: " + leftExpr.interpret() + " 和 " + rightExpr.interpret());this.stack.push(OperatorUtil.getInterpreter(leftExpr, rightExpr,operator));System.out.println("应用运算符: " + operator);}else{NumInterpreter numInterpreter = new NumInterpreter(Integer.valueOf(elements[i]));this.stack.push(numInterpreter);System.out.println("入栈: " + numInterpreter.interpret());}}}private void parse01(String expression) {String [] elements = expression.split(" ");Queue<String> symbols = new LinkedList<>();Queue<String> nums = new LinkedList<>();for (int i = 0; i < elements.length ; i++) {String ele = elements[i];if (OperatorUtil.isOperator(ele)){symbols.offer(ele);} else {nums.offer(ele);}}//先计算乘法Stack<String> nsymbols = new Stack<>();Stack<IArithmeticInterpreter> nnums = new Stack<>();nnums.push(new NumInterpreter(Integer.valueOf(nums.poll())));int symbolLen = symbols.size();for (int j = 0; j < symbolLen; j++) {String operator = symbols.poll();IArithmeticInterpreter next = new NumInterpreter(Integer.valueOf(nums.poll()));if (OperatorUtil.isAddSub(operator)) {nsymbols.push(operator);nnums.push(next);} else {IArithmeticInterpreter previous = nnums.pop();nnums.push(new MultiInterpreter(previous,next));}}//乘法计算完成后的int len = nsymbols.size();IArithmeticInterpreter first = nnums.pop();finalNum.offer(first);for (int h = 0; h < len; h++) {String e = nsymbols.pop();IArithmeticInterpreter pre = finalNum.poll();IArithmeticInterpreter next = nnums.pop();if ("+".equals(e)) {finalNum.offer(new AddInterpreter(pre,next));} else {finalNum.offer(new SubInterpreter(next,pre));}}}public int calculate() {
//        return this.stack.pop().interpret();IArithmeticInterpreter poll = this.finalNum.poll();return poll.interpret();}
}
  • 测试
package com.caozz.demo2.interpreter.calculate;public class Test {public static void main(String[] args) {System.out.println("result(10 + 30): " + new GPCalculator("10 + 30").calculate());System.out.println("result(       50 + 30 - 20       ): " + new GPCalculator("50 + 30 - 20").calculate());System.out.println("result(        2 + 5 * 3         ): " + new GPCalculator("2 + 5 * 3").calculate());System.out.println("result(       2 * 3 + 4 * 5      ): " + new GPCalculator("2 * 3 + 4 * 5").calculate());System.out.println("result(    2 * 3 * 5 + 4 * 5     ): " + new GPCalculator("2 * 3 * 5 + 4 * 5").calculate());System.out.println("result(    2 * 5 + 4 * 5 * 6     ): " + new GPCalculator("2 * 5 + 4 * 5 * 6").calculate());//15 + 15 + 60 = 90System.out.println("result(3 * 5 + 6 + 9 + 2 * 3 * 10): " + new GPCalculator("3 * 5 + 6 + 9 + 2 * 3 * 10").calculate());}}
  • 测试结果
D:\software\java\jdk-17.0.2\bin\java.exe ...
result(10 + 30): 40
result(       50 + 30 - 20       ): 60
result(        2 + 5 * 3         ): 17
result(       2 * 3 + 4 * 5      ): 26
result(    2 * 3 * 5 + 4 * 5     ): 50
result(    2 * 5 + 4 * 5 * 6     ): 130
result(3 * 5 + 6 + 9 + 2 * 3 * 10): 90Process finished with exit code 0
欢迎大家留言,以便于后面的人更快解决问题!另外亦欢迎大家可以关注我的微信公众号,方便利用零碎时间互相交流。共勉!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/46673.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

jmeter---prev.getSamplerData()

JMeter的API-prev.getSamplerData() 该方法用来获取请求的详细信息 假设我的请求如下:用beanshell简单验证下获取的请求:最终打印的结果如下:

k8s安装教程

环境centos7.9 安装地址:https://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/?spm=a2c6h.25603864.0.0.4a85f5adRRKnVY服务器要求: 建议最小硬件配置:2核CPU、2G内存、20G硬盘。 服务器可以访问互联网,会联网下载镜像 初始化配置: 关闭Selinux sed -i s/enforcing/di…

Android无障碍自动化结合opencv实现支付宝能量自动收集

Android无障碍服务可以操作元素,手势模拟,实现基本的控制。opencv可以进行图像识别。两者结合在一起即可实现支付宝能量自动收集。opencv用于识别能量,无障碍服务用于模拟手势,即点击能量。 当然这两者结合不单单只能实现这些,还能做很多自动化的程序,如芭芭农场自动施肥…

域渗透之ATTCK实战系列——红队实战(一)

这个靶场是红日安全团队推出的红队实战系列第一个靶场,其中包括了漏洞利用、内网搜集、横向移动、构建通道、持久控制等多个环节。目录前言环境搭建外围打点信息收集phpmyadmin全局日志getshell内网信息收集msf上线mimikatz抓取明文密码&hash域信息收集横向移动msf+proxyc…

1. hello rvos

用qemu模拟器模拟一块仿真的板子,然后通过模拟的串口线,在主机上打印hello在qemu中,关于uart寄存器的内存映射如图(物理地址)1. 源代码剖析 1. platform.h 用来定义开发板上的一些东西 #ifndef __PLATFORM_H__ #define __PLATFORM_H__ //这些宏用于防止重复包含头文件。#i…

基于鲸鱼优化的knn分类特征选择算法matlab仿真

1.程序功能描述基于鲸鱼优化的KNN分类特征选择算法。使用鲸鱼优化算法,选择最佳的特征,进行KNN分类,从而提高KNN分类的精度。2.测试软件版本以及运行结果展示 MATLAB2022a版本运行 3.核心程序%---开始迭代--------------------------------------------------- while t &…

UNIQUE VISION Programming Contest 2024 Summer (AtCoder Beginner Contest 359) 题解

点我看题 A - Count Takahashi 没啥好说的点击查看代码 #include <bits/stdc++.h>#define rep(i,n) for(int i=0;i<n;++i) #define repn(i,n) for(int i=1;i<=n;++i) #define LL long long #define fi first #define se second #define pb push_back #define mpr m…

20240622-PowerShell5和PowerShell7在windows terminal中无法切换

今天安装powertoys小工具commandNotFound的时候,提示要求powershell版本是7,而当前powershell版本是5,如下。但是powertoys中显示powershell7已经安装,如下图。主要问题在于powershell5的程序名是 powershell.exe, 而powershell7的程序名是pwsh.exe. windows terminal每个选…