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

news2024/11/23 19:07:24

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

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.coloradmin.cn/o/1794406.html

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

相关文章

【探索全球精彩瞬间,尽享海外短剧魅力!海外短剧系统,您的专属观影平台】

&#x1f31f; 海外短剧系统&#xff0c;带您走进一个全新的视界&#xff0c;让您随时随地欣赏到来自世界各地的精选短剧。在这里&#xff0c;您可以感受到不同文化的碰撞&#xff0c;品味到各种题材的精髓&#xff0c;让您的生活更加丰富多彩&#xff01; &#x1f3ac; 精选…

19 - 查询结果的质量和占比(高频 SQL 50 题基础版)

19 - 查询结果的质量和占比 -- round(avg(rating<3)*100,2)round(avg(if(rating<3,1,0))*100,2) select query_name,round(avg(rating/position),2) quality,round(avg(if(rating<3,1,0))*100,2) poor_query_percentage fromQueries group byquery_name;

数据分析第一天(pandas简单的对快餐店数据进行操作获得想要的信息,使用apply,groupby)

前言 数据保存在 https://github.com/harkbox/DataAnalyseStudy 数据名称&#xff1a;快餐数据.tsv &#xff08;tsv是用\t作为字符分隔符的文件格式&#xff1b;csv是逗号&#xff09; 因此可以用pandas的read_csv函数读取数据 1.读取数据 import pandas as pd import matp…

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

YOLOv8_obb的预测流程,主要分预处理模块、推理模块和后处理模块。这里面有很多内容是和目标检测预测流程是重合的,主要区别在于Angle分支、NMS后处理以及regularize_rboxes部分。本文也主要介绍一下这三个模块,其他模块可以结合YOLOv8预测流程-原理解析[目标检测理论篇]一起…

跟TED演讲学英文:Your right to repair AI systems by Rumman Chowdhury

Your right to repair AI systems Link: https://www.ted.com/talks/rumman_chowdhury_your_right_to_repair_ai_systems Speaker: Rumman Chowdhury Date: April 2024 文章目录 Your right to repair AI systemsIntroductionVocabularySummaryTranscriptAfterword Introduct…

电脑响度均衡是什么?它如何开启?

什么是响度均衡 响度均衡&#xff08;Loudness Equalization&#xff09;是一种音频处理技术&#xff0c;旨在平衡音频信号的响度水平&#xff0c;使得不同音源在播放时具有相似的响度感受。简单来说&#xff0c;它可以让用户在播放不同音轨或音频内容时&#xff0c;不需要频繁…

IGraph使用实例——线性代数计算(blas)

1 概述 在图论中&#xff0c;BLAS&#xff08;Basic Linear Algebra Subprograms&#xff09;并不直接应用于图论的计算&#xff0c;而是作为一套线性代数计算中通用的基本运算操作函数集合&#xff0c;用于进行向量和矩阵的基本运算。然而&#xff0c;这些基本运算在图论的相…

深度神经网络——什么是扩散模型?

1. 概述 在人工智能的浩瀚领域中&#xff0c;扩散模型正成为技术创新的先锋&#xff0c;它们彻底改变了我们处理复杂问题的方式&#xff0c;特别是在生成式人工智能方面。这些模型基于高斯过程、方差分析、微分方程和序列生成等坚实的数学理论构建。 业界巨头如Nvidia、Google…

python API自动化(接口测试基础与原理)

1.接口测试概念及应用 什么是接口 接口是前后端沟通的桥梁&#xff0c;是数据传输的通道&#xff0c;包括外部接口、内部接口,内部接口又包括&#xff1a;上层服务与下层服务接口&#xff0c;同级接口 外部接口&#xff1a;比如你要从 别的网站 或 服务器 上获取 资源或信息 &a…

网站调用Edge浏览器API:https://api-edge.cognitive.microsofttranslator.com/translate

Edge浏览器有自带的翻译功能&#xff0c;在运行pc项目可能会遇到疯狂调用Edge的API https://api-edge.cognitive.microsofttranslator.com/translate 这个URL&#xff08;https://api-edge.cognitive.microsofttranslator.com/translate&#xff09;指向的是微软服务中的API接…

OpenCV中的圆形标靶检测——背景概述

圆形标靶 如下图所示,相机标定中我们使用带有固定间距图案阵列的平板,来得到高精度的标靶像素坐标,进而计算得到相机的内参、畸变系数,相机之间的变换关系,和相机与世界坐标系的变换关系(即外参)。 不过标靶的形式多样,从图案类型来看常见的有棋盘格、圆形标靶…

Paper Survey——3DGS-SLAM

之前博客对多个3DGS SLAM的工作进行了复现及代码解读 学习笔记之——3DGS-SLAM系列代码解读_gs slam-CSDN博客文章浏览阅读1.9k次&#xff0c;点赞15次&#xff0c;收藏45次。最近对一系列基于3D Gaussian Splatting&#xff08;3DGS&#xff09;SLAM的工作的源码进行了测试与…

windows根据时间自定义默认应用模式

Target 将“默认应用模式“能否设置为早上7点为“亮”&#xff0c;到了晚上7点设置为“暗”&#xff0c;每天都执行以下这个任务。 这样我的很多应用软件(e.g., chrome, explorer)就可以到点变黑&#xff0c;到点变白了 ChatGPT answer (亲测有效): 你可以使用Windows的任务计…

记录遇见的小问题

1&#xff0c;angularjs 使用bootstrap时&#xff0c;遇见模态框怎么点击空白处不关闭&#xff1b; <div id"dialog-modal" data-backdrop"static" data-keyboard"false"> 但是在实际使用过程中调用了一个html 需要在 js里加 $scope.Up…

【Elasticsearch】es基础入门-03.RestClient操作文档

RestClient操作文档 示例&#xff1a; 一.初始化JavaRestClient &#xff08;一&#xff09;引入es的RestHighLevelClient依赖 <!--elasticsearch--> <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest…

【UE+GIS】UE5GIS CAD或shp构建3D地形

贴合地形的矢量图形实现方法 一、灰度图的制作和拉伸换算1、基于高程点集实现2、基于等高线实现3、拉伸计算 二、生成地形模型的实现方案1、3Dmax导入灰度图2、使用ArcMap/Arcpro/FME等GIS数据处理工具3、UE导入灰度图 三、地形上叠加地形渲染效果的实现方案1、贴花2、数据渲染…

矩阵链相乘(动态规划法)

问题分析 矩阵链相乘问题是一个经典的动态规划问题。给定一系列矩阵&#xff0c;目标是找到一种最优的乘法顺序&#xff0c;使得所有矩阵相乘所需的标量乘法次数最少。矩阵链相乘问题的关键在于利用动态规划来避免重复计算子问题。 算法设计 定义子问题&#xff1a;设 &…

ETL or iPaaS,企业数据集成工具选择攻略

随着信息技术的飞速发展&#xff0c;企业对于数据的处理和分析需求愈发强烈&#xff0c;数据集成作为实现数据价值的重要手段&#xff0c;其技术和工具的选择成为业界关注的焦点。 传统ETL&#xff08;Extract, Transform, Load&#xff09;数据集成方法长期以来被广泛应用。然…

探索数据结构:堆,计数,桶,基数排序的分析与模拟实现

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;数据结构与算法 贝蒂的主页&#xff1a;Betty’s blog 1. 堆排序 1.1. 算法思想 堆排序(Heap Sort)是一种基于堆数据结构的排…

在IDEA中使用Git在将多次commit合并为一次commit

案例&#xff1a; 我想要将master分支中的 测试一、测试二、测试三三次commit合并为一次commit 1. 点击Git 2. 双击点击commit所在的分支 3. 右键要合并的多个commit中的第一次提交的commit 4. 点击右键后弹出的菜单中的Interactively Rebase From Here选项 5. 点击测试二…