【再探】设计模式—备忘录模式与解释器模式

 备忘录模式是用于保存对象在某个时刻的状态,来实现撤销操作。而解释器模式则是将文本按照定义的文法规则解析成对应的命令。

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;;
        }

        @Override
        public 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 优缺点

优点:

  1. 提供了一种状态恢复机制,对象可以方便地回到一个特定的历史步骤状态。

缺点:

  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 {
        @Override
        int 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 {
        @Override
        int 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. 执行效率较低,使用了大量的循环和递归调用,调试过程比较麻烦。
  2. 复杂文法难以维护。如果一种语言包含太多文法规则,类的数量将会急剧增加,导致系统难以管理和维护。

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

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

相关文章

Anaconda创建python环境默认C盘,如何修改路径

文章目录 前言解决方案1.找到Anaconda的根目录2. 找到根目录文件夹&#xff0c;右键-属性-安全 测试-重新创建新的python环境 前言 使用 Anaconda创建python环境&#xff0c;默认在C盘。 如何修改到别的路径呢&#xff1f; base环境 是安装 Anaconda是安装的默认环境&#x…

YOLOv8_obb训练流程-原理解析[旋转目标检测理论篇]

在旋转目标检测网络中,换了个顺序,先把训练流程捋一遍,然后再取捋一下测试的流程。由下图的YOLOv8l_obb网络结构图可以看到相对于目标检测网络,旋转目标检测网络只是在Head层不相同,在每个尺度特征层中增加了Angle分支(浅蓝色),通过两个卷积组和一个Conv卷积得到得到通…

隐马尔可夫链

1 马尔可夫链 马尔科夫链&#xff08;Markov Chain&#xff09;是一种数学模型&#xff0c;它描述了一系列可能事件的概率&#xff0c;其中每个事件的发生仅依赖于前一个事件的状态。这一特性称为“无记忆性”或“马尔可夫性质”。我将用一个简单的天气预测模型作为例子来解释马…

Docker的网络管理

文章目录 一、Docker容器之间的通信1、直接互联&#xff08;默认Bridge网络&#xff09;1.1、Docker安装后默认的网络配置1.2、创建容器后的网络配置1.2.1、首先创建一个容器1.2.2、ip a 列出网卡变化信息1.2.3、查看新建容器后的桥接状态 1.3、容器内安装常见的工具1.4、容器间…

记一次线上数据库连接超时异常问题

最近其他团队的开发人员告知我&#xff0c;我们项目有个feign接口调用失败了。我查看日志发现&#xff0c;其原因是尝试数据库连接超时&#xff0c;30秒内都没有连接成功。 我首先判断可能是网络不稳定&#xff0c;在一定时间内连接不上数据库。我登录到服务器环境看&#xff0…

内网域中NTLM中继那些事儿

0x01 初识NTLM协议 基本概念&#xff1a;NTLM(NT LAN Manager)认证是一种早期的Windows网络身份认证协议。它在Windows系统中用于验证用户的身份&#xff0c;并提供对网络资源的访问控制&#xff0c;它是一种基于Challenge/Response的认证机制。 认证流程 NTLM协议Challenge…

如何使用 DANN 改进神经网络

文章目录 一、说明二、语言模型真的理解语言吗&#xff1f;三、了解分配转变3.1 样本选择偏差3.2 非静止环境3.3 领域适配挑战3.4 概念漂移 四、对领域对抗训练的介绍 一、说明 由于其多功能性&#xff0c;神经网络是大多数现代机器学习管道的主要内容。他们处理非结构化数据的…

mathtype7最新产品密钥激活2024最新

MathType是一款专业的数学公式编辑器&#xff0c;广泛应用于教育、科研和出版等领域。随着在线教育和远程工作的兴起&#xff0c;MathType的使用场景更加广泛&#xff0c;成为教师、学生、研究人员和专业作家必不可少的工具之一。本文将详细介绍MathType的功能特点、操作步骤以…

HTML 总结

HTML 简介 HTML(HyperText MarkupLanguage): 超文本标记语言 超文本 : 普通文本指的是只有文字没有图片 ,视频, 音乐,而超文本就有 标记语言 : 由标签构成的语言 HTML的标签都是预定好的, 如<a> </a> 为超链接 HTML代码直接在浏览器中运行,由浏览器内核进行解…

C++自定义String类

自定义一个String类型,该类包含一个指向字符串的指针和一个统计对象数量的计数器. 代码如下: //string.h #pragma once //String类型 #include <iostream> using namespace std;class String { private:char* m_str;//保存字符串的地址static int num_strings;//创建的对…

Nginx服务的主配置文件及配置举例

Nginx服务的主配置文件 安装Nginx认识Nginx服务全局配置I/O 事件配置HTTP 配置日志格式设定 访问状态统计配置查看Nginx已安装模块修改 nginx.conf 配置文件重启服务&#xff0c;访问测试 基于授权的访问控制准备用户密码认证文件修改 nginx.conf 配置文件重启服务&#xff0c;…

Xcode下载安装

1.Xcode可用版本判断&#xff1a; 2.Xcode下载安装&#xff1a; 方案1:AppStore 下载更新 若方案1失败则 方案2:指定版本Xcode包下载解压安装 苹果下载 3.Xcode命令行工具插件安装 xcode-select --install 备注&#xff1a; xcode_x.x.x.xip(压缩包存在时效性(使用前24h/…

【目录扫描】feroxbuster v2.10.2 字典整合版

# 简介 Feroxbuster是一款强大的目录扫描工具&#xff0c;Feroxbuster的主要功能是基于字典的目录扫描&#xff0c;并且默认使用Seclists字典进行使用&#xff01;并且具有快速和高效的特点&#xff0c;采用了多线程的技术来加快扫描速度。还支持暂停交互式设置等&#xff01;…

从一个猜数游戏开始

标题 一、从源码中学习1.1 源码1.2 运行结果 二、 导入一个trait三、重要源码分析 一、从源码中学习 1.1 源码 一个简单的猜数大小游戏&#xff0c;不集的输入&#xff0c;直到猜测正确时退出。 use rand::Rng; use std::cmp::Ordering; use std::io;fn main() {let secret_…

解锁自动化文档转换:Python-Markdown的魔法

文章目录 解锁自动化文档转换&#xff1a;Python-Markdown的魔法背景Python-Markdown是什么&#xff1f;如何安装Python-Markdown&#xff1f;Python-Markdown库函数使用方法场景应用示例常见问题与解决方案总结 解锁自动化文档转换&#xff1a;Python-Markdown的魔法 背景 在…

【Leetcode每日一题】 动态规划 - 简单多状态 dp 问题 - 买卖股票的最佳时机含冷冻期(难度⭐⭐)(79)

1. 题目解析 题目链接&#xff1a;309. 买卖股票的最佳时机含冷冻期 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 二、算法思路 1. 状态表示 dp[i][0]&#xff1a;表示第 i 天结束后&#xff0c;处于「买入」状态…

总结2024.6.2

最近&#xff0c;还没受到offer&#xff0c;找工作找到自闭。在找工作的过程中&#xff0c;也听到一些面试官问我的职业生涯规划。这也让我陷入了沉思。自从考研结束后&#xff0c;都是被这个社会推着走的。我当初也想过自己要从事什么工作&#xff0c;不过&#xff0c;后面还是…

Mysql常见问题总结

1、MySQL初始化报错 mysqld --initialize --usermysql --console 2024-06-02T15:52:22.645557Z 0 [System] [MY-013169] [Server] D:\installSoft\mysql-8.0.21-winx64\bin\mysqld.exe (mysqld 8.0.21) initializing of server in progress as process 8980 2024-06-02T15:52:2…

向量叉乘的方向

向量叉乘的方向 最近在百度上看到这样一个帖子&#xff1a; 可以根据这个判断是顺时针还是逆时针的 ab的方向&#xff1a;四指由a开始&#xff0c;指向b&#xff0c;拇指的指向就是ab的方向&#xff0c;垂直于a和b所在的平面&#xff1b; ba的方向&#xff1a;四指由b开始&a…

驾校-短视频营销招生精品课:抖音推广技巧,抖音短视频招生(41节课)

课程下载&#xff1a;驾校-短视频营销招生精品课&#xff1a;抖音推广技巧&#xff0c;抖音短视频招生(41节课)-课程网盘链接提取码下载.txt资源-CSDN文库 更多资源下载&#xff1a;关注我。 课程内容&#xff1a; 课程目录 [1]-第1课驾校为什么要全力做好短视频营销.mp4 …