【再探】设计模式—备忘录模式与解释器模式
备忘录模式是用于保存对象在某个时刻的状态,来实现撤销操作。而解释器模式则是将文本按照定义的文法规则解析成对应的命令。
1 备忘录模式
需求:保存对象在某个时刻的状态,后面可以对该对象实行撤销操作。
1.1 备忘录模式介绍
提供一种状态恢复机制,在不破坏封装的前提下,捕获对象内部状态并在该对象之外保存这个状态。可以在以后将对象恢复到原先保存的状态。

图 备忘录模式 UML
public class MementoPattern {public static void main(String[] args) {String[] colors = {"red","blue","green","pink","black"};Button button = new Button();Random random = new Random();MementoCareTaker<ButtonMemento> careTaker = new MementoCareTaker<>();for (int i = 0; i < 10; i++) {button.setColor(colors[random.nextInt(colors.length)]);button.setPositionX(random.nextDouble());careTaker.pushMemento(button.createMemento());}button.restoreFromMemento(careTaker.getMemento(2));System.out.println(button);button.restoreFromMemento(careTaker.getMemento(3));System.out.println(button);button.restoreFromMemento(careTaker.getMemento(1));System.out.println(button);}private static class Button {private String color;private Double positionX;public String getColor() {return color;}public void setColor(String color) {this.color = color;}public Double getPositionX() {return positionX;}public void setPositionX(Double positionX) {this.positionX = positionX;}public ButtonMemento createMemento() {return new ButtonMemento(color,positionX);}public void restoreFromMemento(ButtonMemento memento) {this.color = memento.getColor();this.positionX = memento.positionX;;}@Overridepublic String toString() {return "Button{" +"color='" + color + '\'' +", positionX=" + positionX +'}';}}private static class ButtonMemento {private final String color;private final Double positionX;public ButtonMemento(String color, Double positionX) {this.color = color;this.positionX = positionX;}public String getColor() {return color;}public Double getPositionX() {return positionX;}}private static class MementoCareTaker<T> {private final Stack<T> stack = new Stack<>();public void pushMemento(T t) {stack.push(t);}public T getMemento(int num) {T t = null;while (num-- > 0 && !stack.isEmpty()) {t = stack.pop();}return t;}}}
1.2 优缺点
优点:
- 提供了一种状态恢复机制,对象可以方便地回到一个特定的历史步骤状态。
缺点:
- 需要保存不同时刻的对象状态,这将耗费许多内存等资源。
- 类的数量增多,当对象自带有变动时,对应的备忘类也需要修改。
2 解释器模式
需求:将文本按照特定的语法规则转换成计算机中特定的命令。
2.1 解释器模式介绍
定义一个语言的文法,并建立一个解释器来解释该语言中的句子。这里的“语言”是指使用特定格式和语法的代码。

图 解释器UML
这里的Context 一般用于存储解释器之外的一些全局信息,也可以省略这个类。
| ::= | 定义为。 |
| | | 或。 |
| ‘{’和‘}’ | 组合。 |
| * | 出现0或多次。 |
| 语言单位 | 语言构造成分,每一条语句所定义的字符串。 |
| 终结表达式 | 组成元素是最基本的语言单位,不能在进行分解。 |
| 非终结表达式 | 组成元素仍可以是表达式,可进一步分解。 |
图 文法规则说明
public class InterpreterPattern {/*** 语法规则:* value ::= a integer* operator ::= '+' | '-' | '*' | '/'* expression ::= value operator value | complexExpression* complexExpression ::= expression operator expression | expression operator (expression)*/public static void main(String[] args) {String[] textArr = {"1+4*3","4*5+3","(3+4)*23", "(3+24)-(23-8)", "(2-3)*(24+2*3)", "(((1+2)*(2+3)))+32"};for (int i = 0; i < textArr.length; i++) {System.out.print(textArr[i]);System.out.println("=" + new ComplexExpression().interpreter(textArr[i]));}}private static abstract class Expression {abstract int interpreter(String text);protected int compute(int leftNum,int rightNum,char opera) {switch (opera) {case '+': return leftNum + rightNum;case '-': return leftNum - rightNum;case '*': return leftNum * rightNum;case '/': return leftNum / rightNum;}return 0;}}/*** 复杂表达式*/private static class ComplexExpression extends Expression {@Overrideint interpreter(String text) {
// System.out.println("ComplexExpression:" + text);int letNum=0;int rightNum=0;char opera = ' ';Pattern pattern = Pattern.compile("[\\+\\-\\*\\/]");Matcher matcher = pattern.matcher(text);if (matcher.find()) {int start = matcher.start();opera = text.charAt(start);if (text.indexOf("(") == 0) { // 在操作符前面有括号, 先计算括号的内容int endBracketPos = findEndBracketPos(text);letNum = new ComplexExpression().interpreter(text.substring(1,endBracketPos));if (endBracketPos == text.length() -1 ) {return letNum;}opera = text.charAt(endBracketPos+1);rightNum = new ComplexExpression().interpreter(text.substring(endBracketPos+2));} else if ((opera == '*' || opera == '/') && text.charAt(start+1) != '(') { // 需要先完成左边运算boolean hasNext = matcher.find(start + 1);if (hasNext) {int pos2 = matcher.start();letNum = new ComplexExpression().interpreter(text.substring(0,pos2));opera = text.charAt(pos2);rightNum = new ComplexExpression().interpreter(text.substring(pos2+1));} else {letNum = new TerminalExpression().interpreter(text.substring(0,start));rightNum = new ComplexExpression().interpreter(text.substring(start+1));}} else {letNum = new TerminalExpression().interpreter(text.substring(0,start));rightNum = new ComplexExpression().interpreter(text.substring(start+1));}return compute(letNum,rightNum,opera);} else { // 终结表达式return new TerminalExpression().interpreter(text);}}private int findEndBracketPos(String text) {int startPos = 0,endPos = 0;do {endPos = text.indexOf(")",endPos+1);startPos = text.indexOf("(",startPos+1);} while (startPos < endPos && startPos > 0);return endPos;}}/*** 是一个数值 或者 是 (数值) 形式,要把text 转换为数值*/private static class TerminalExpression extends Expression {@Overrideint interpreter(String text) {
// System.out.println("TerminalExpression:" + text);if (text.indexOf("(") == 0) {text = text.substring(1,text.length() - 1);}return Integer.parseInt(text);}}}
2.2 优缺点
优点:
- 实现文法较为容易。易于改变和扩展文法。增加新的解释表达式较为方便,只需增加相关表达式类即可,符合开闭原则。
缺点:
- 执行效率较低,使用了大量的循环和递归调用,调试过程比较麻烦。
- 复杂文法难以维护。如果一种语言包含太多文法规则,类的数量将会急剧增加,导致系统难以管理和维护。
相关文章:
【再探】设计模式—备忘录模式与解释器模式
备忘录模式是用于保存对象在某个时刻的状态,来实现撤销操作。而解释器模式则是将文本按照定义的文法规则解析成对应的命令。 1 备忘录模式 需求:保存对象在某个时刻的状态,后面可以对该对象实行撤销操作。 1.1 备忘录模式介绍 提供一种状…...
SpringCloud网关-gateway
一 什么是网关?为什么选择 Gateway? 网关功能如下: 身份认证和权限校验服务路由、负载均衡请求限流 在 Spring Cloud 中网关的实现包含两种: Gateway(推荐):是基于 Spring5 中提供的 WebFlux ÿ…...
LiveData是如何感知Room数据变化的
一 Room数据变化LiveData如何收到onChanged回调的? 1.1 LiveData是如何创建的 这里讨论的LiveData的创建是特指Dao定义的方法的返回类型,而不是所有的LiveData。 以NoteDao 举例: Dao public interface NoteDao {Query("select * fr…...
【自动化】WebUI自动化通过读取用户数据的方式启动浏览器实现绕过相关登录验证的方法。
背景说明 我相信做自动化测试或者实现UI自动化相关功能的同学肯定碰到过,每次写好脚本执行时都是默认打开一个 “新”的浏览器,我的意思是就跟刚下载的浏览器一样。而不是平时日常使用着的浏览器的状态,日常使用浏览器时只要近期登录过&…...
信号:干扰类别及特征提取
目录 第一部分:干扰类别 1.压制干扰 1.1噪声调幅瞄准式干扰(单音干扰) 1.2噪声调频阻塞式干扰(宽带噪声干扰) 1.3噪声调频扫频式干扰(线性调频) 2.欺骗干扰 2.1距离欺骗干扰(幅度调制干扰࿰…...
【推荐】用scss循环zoom缩放比例,解决可视化大屏在不同分辨率屏幕下的适配问题
方法1: 指定几种常规屏幕宽度(用这种方式就必须要强制用户全屏查看页面,在固定的宽度下才能达到比较不错的显示效果) // 适配不同分辨率的页面---------------------------------------- html {overflow: hidden;width: 1920px;…...
23中设计模式之一— — — —命令模式的详细介绍
命令模式 Command Pattern讲解 概念描述模式结构主要角色模式的UIM类图模式优点模式缺点应用场景实例演示类图代码演示运行结果 概念 命令模式(别名:动作,事务) 命令模式是一种行为设计模式,将一个请求封装为一个对象…...
解决 Mac Django 连接Mysql 出现 image not found 问题
最近在使用 Django 框架,因为升级到4.2版本了,对应的本机 Mysql 5.7 就不适用了,于是升级到了 Mysql 8.0,写好代码之后出现如下错误: 仔细分析一下错误的描述: ImportError: dlopen(/Library/Frameworks/P…...
EitbaseEX香港业务开展,提升用户友好交易体验
在全球范围内备受瞩目的加密货币交易平台Coinbase,宣布正式入驻香港市场,并命名为EitbaseEX。这一战略性扩展举措,旨在为香港提供先进的加密货币交易技术和服务,同时将香港打造为其在亚太地区的重要枢纽。 作为国际金融中心&#…...
ROS学习记录:自定义消息类型
前言 当我们需要传输一些特殊的数据时,且官方的消息包无法满足需求,我们便可以自己定义一个消息类型。 实验步骤 一、在终端输入cd ~/catkin_ws1/src进入工作空间中src目录 二、输入catkin_create_pkg qq_msgs roscpp rospy std_msgs message_generati…...
创新实训2024.06.06日志:部署web服务
1. 运行web项目前后端服务 首先我们要先在服务器上运行客户端以及服务端的应用程序。随后再考虑如何通过公网/局域网访问的问题。 如何启动服务在仓库对应分支下的Readme文件中已经有详细描述了。 1.1. 启动服务端 对于服务端,即(要求你在服务端子项…...
使用C++实现YOLO图像分类:从环境搭建到性能评估的完整指南
⭐️我叫忆_恒心,一名喜欢书写博客的研究生👨🎓。 如果觉得本文能帮到您,麻烦点个赞👍呗! 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三连支…...
Linux中安装Docker,并使用Docker安装MySQL和Redis
1、安装docker 1卸载系统之前的docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine2、安装Docker-CE #安装必须的依赖 sudo yum install -y yum-utils \device-map…...
期货短线交易的核心技术是什么
一、市场分析是短线交易的基础: 技术分析在短线交易中尤为重要,包括K线图、均线系统、成交量与持仓量等指标。K线图可以帮助交易者识别关键价格形态和趋势线,从而判断市场走势。均线系统则可以利用短期均线交叉作为买卖信号,如金…...
VSCode+Vite+Vue3断点调试
目录 lunch.json创建 vite.config.ts 打断点运行 lunch.json创建 首先,点击VSCode左上角,甲壳虫运行的按钮,然后点击运行与调试,选择chrome浏览器,修改成一下配置。 { // 使用 IntelliSense 了解相关属性。 // 悬停…...
RPC框架原理(一)
RPC框架原理 网络和IO的关系,IO(input和output)面向的是谁?OSI 7层参考模型,TCP/IP协议为什么会出现一个会话层三次握手socket心跳keep alive四次挥手 网络IO(IO模型) IO框架底层 学习顺序&…...
LCTF 2018 bestphp‘s revenge
考点:Soap原生类Session反序列化CRLF注入 <?php highlight_file(__FILE__); $b implode; call_user_func($_GET[f], $_POST); session_start(); if (isset($_GET[name])) { $_SESSION[name] $_GET[name]; } var_dump($_SESSION); $a array(reset($_…...
MySQL主从搭建--保姆级教学
MYSQL主从搭建步骤 主节点 # 进入目录 cd /opt# 下载安装包 wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz# 解压 tar -xvf mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz# 拷贝到/usr/local mv /opt/mysql-8.0.20-linux-g…...
Modbus通信协议--RTU
一、RTU介绍 MODBUS协议支持多种功能码,不同的功能码对应不同的操作: 0x01读线圈状态0x02读离散输入状态0x03读保持寄存器0x04读输入寄存器0x05写单个线圈0x06写单个保持寄存器0x0F写多个线圈0x10写多个保持寄存器 二、实验 1.0x03功能码读单个保持寄…...
我是大学生,应该选系统运维方向,还是web开发方向?
选择系统运维方向还是Web开发方向取决于你的兴趣、职业目标和个人技能。以下是对这两个方向的详细对比和建议,帮助你做出更明智的选择 双方比较 🤦♀️系统运维方向 优点: 稳定性:系统运维工作通常比较稳定,许多…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
PostgreSQL——环境搭建
一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在࿰…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...
论文阅读:Matting by Generation
今天介绍一篇关于 matting 抠图的文章,抠图也算是计算机视觉里面非常经典的一个任务了。从早期的经典算法到如今的深度学习算法,已经有很多的工作和这个任务相关。这两年 diffusion 模型很火,大家又开始用 diffusion 模型做各种 CV 任务了&am…...
