设计模式Python版 备忘录模式
文章目录
- 前言
- 一、备忘录模式
- 二、备忘录模式示例1
- 三、备忘录模式示例2
前言
GOF设计模式分三大类:
- 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。
- 结构型模式:关注类和对象之间的组合,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。
- 行为型模式:关注对象之间的交互,包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。
一、备忘录模式
备忘录模式(Memento Pattern)
-
定义:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
-
解决问题:如何在软件中实现撤销功能?
-
使用场景:
- 保存一个对象在某一个时刻的全部状态或部分状态,这样以后需要时就能够恢复到先前的状态,实现撤销操作。
- 防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态的实现细节暴露给外界对象。
-
组成:
- Originator(原发器):它是一个普通类,可以创建一个备忘录,并存储其当前内部状态,也可以使用备忘录来恢复其内部状态。一般将需要保存内部状态的类设计为原发器。
- Memento(备忘录):存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用。
- Caretaker(负责人):负责人又称为管理者,他负责保存备忘录,但是不能对备忘录的内容进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,他只负责存储对象,而不能修改对象,也无须知道对象的实现细节。
-
补充说明:
- 撤销功能的实现原理:在实现撤销时,首先必须保存软件系统的历史状态。当用户需要取消错误操作并且返回到某个历史状态时,可以取出事先保存的历史状态来覆盖当前状态。
- 通过使用备忘录模式可以使系统恢复到某一特定的历史状态。当前很多软件都提供了撤销(Undo)操作,其中就使用了备忘录模式。
- 备忘录模式的核心是备忘录类以及用于管理备忘录的负责人类的设计。
- 在真实业务中,原发器类是一个具体的业务类,它包含一些用于存储成员数据的属性。
- 对于备忘录类Memento而言,它通常提供了与原发器相对应的属性(可以是全部,也可以是部分)用于存储原发器的状态。
- 对于负责人类Caretaker,它用于保存备忘录对象,并提供getMemento()方法用于向客户端返回一个备忘录对象。
-
优点:
- 它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤。
- 备忘录实现了对信息的封装。
-
缺点:
- 资源消耗过大
二、备忘录模式示例1
使用备忘录模式来设计中国象棋软件,提供“悔棋”功能
- Chessman充当原发器,ChessmanMemento充当备忘录,MementoCaretaker充当负责人
- 在MementoCaretaker中定义了一个ChessmanMemento类型的对象,用于存储备忘录。
### 备忘录模式
"""原发器:象棋棋子"""class Chessman:def __init__(self, label: str, x: int, y: int):self.label = labelself.x = xself.y = ydef save(self) -> "ChessmanMemento":# 保存状态return ChessmanMemento(self.label, self.x, self.y)def restore(self, memento: "ChessmanMemento"):# 恢复状态self.label = memento.labelself.x = memento.xself.y = memento.y"""备忘录:象棋棋子备忘录"""class ChessmanMemento:def __init__(self, label: str, x: int, y: int):self.label = labelself.x = xself.y = y"""负责人:象棋棋子备忘录管理"""class MementoCaretaker:def __init__(self):self.memento: ChessmanMemento = Nonedef get_memento(self):return self.mementodef set_memento(self, memento: ChessmanMemento):self.memento = memento
- 客户端代码
def display(chess: Chessman):print(f"棋子 {chess.label} 当前位置为:行 {chess.x} 列 {chess.y}")if __name__ == "__main__":mc = MementoCaretaker()chess = Chessman("车", 2, 2)display(chess)mc.set_memento(chess.save()) # 保存状态chess.y = 4display(chess)mc.set_memento(chess.save()) # 保存状态chess.x = 5display(chess)print("###悔棋###")chess.restore(mc.get_memento()) # 恢复状态display(chess)
- 输出结果
棋子 车 当前位置为:行 2 列 2
棋子 车 当前位置为:行 2 列 4
棋子 车 当前位置为:行 5 列 4
###悔棋###
棋子 车 当前位置为:行 2 列 4
三、备忘录模式示例2
实现多次撤销
- 在负责人类中定义列表来存储多个备忘录。修改负责人代码:
"""负责人:象棋棋子备忘录管理"""
class MementoCaretaker:def __init__(self):self.memento_list_f: list[ChessmanMemento] = [] # 前进状态self.memento_list_b: list[ChessmanMemento] = [] # 悔棋状态def get_memento_f(self):# 用于悔棋self.memento_list_b.append(self.memento_list_f.pop())return self.memento_list_f[-1]def get_memento_b(self):# 用于撤销悔棋memento = self.memento_list_b.pop()self.memento_list_f.append(memento)return mementodef set_memento(self, memento: ChessmanMemento):# 下棋保存状态self.memento_list_b.clear() # 棋子前进,则清空悔棋状态self.memento_list_f.append(memento)
- 客户端代码
def display(chess: Chessman):print(f"棋子 {chess.label} 当前位置为:行 {chess.x} 列 {chess.y}")def play(chess: Chessman, mc: MementoCaretaker):# 下棋mc.set_memento(chess.save()) # 保存备忘录display(chess)def undo(chess: Chessman, mc: MementoCaretaker):# 悔棋print("###悔棋###")chess.restore(mc.get_memento_f())display(chess)def redo(chess: Chessman, mc: MementoCaretaker):# 撤销悔棋print("###撤销悔棋###")chess.restore(mc.get_memento_b())display(chess)if __name__ == "__main__":mc = MementoCaretaker()chess = Chessman("车", 1, 1)play(chess, mc)chess.y = 4play(chess, mc)chess.x = 5play(chess, mc)undo(chess, mc)undo(chess, mc)redo(chess, mc)redo(chess, mc)
- 输出结果
棋子 车 当前位置为:行 1 列 1
棋子 车 当前位置为:行 1 列 4
棋子 车 当前位置为:行 5 列 4
###悔棋###
棋子 车 当前位置为:行 1 列 4
###悔棋###
棋子 车 当前位置为:行 1 列 1
###撤销悔棋###
棋子 车 当前位置为:行 1 列 4
###撤销悔棋###
棋子 车 当前位置为:行 5 列 4
您正在阅读的是《设计模式Python版》专栏!关注不迷路~
相关文章:
设计模式Python版 备忘录模式
文章目录 前言一、备忘录模式二、备忘录模式示例1三、备忘录模式示例2 前言 GOF设计模式分三大类: 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式:…...
CES Asia 2025聚焦量子计算,多领域进展引关注
作为亚洲地区极具影响力的科技盛会,CES Asia 2025第七届亚洲消费电子技术贸易展(赛逸展)将在首都北京举办。本届展会以“创新、智能、互联”为主题,将全方位展示全球消费科技领域的最新成果与发展趋势。其中,量子计算作…...
MySQL索引深度剖析:从数据结构到实际应用
引言 在数据库系统中,索引是提高查询效率的关键技术之一。MySQL作为最流行的关系型数据库之一,其索引机制尤为重要。本文将剖析MySQL索引的数据结构、分类、创建方式以及实际应用场景,帮助读者更好地理解和应用索引技术。 主体部分 1. MyS…...
【deepseek】本地部署+RAG知识库挂载+对话测试
文章目录 前言一、Deepseek模型下载(以7B为例)二、RAG本地知识库挂载三、创建本地对话脚本四、结果展示 前言 本文主要涵盖Deepseek在ubuntu系统中的部署全流程,包括模型的下载、系统部署、本地文档向量化、向量列表存储、RAG知识库挂载、对话测试等内容 一、Deeps…...
Vue.js 组件开发全面详解及应用案例
Vue.js 的组件化开发是其核心特性之一,使得代码复用、维护和扩展变得更加容易。以下是关于 Vue.js 组件开发的全面解析,并附带一个实际应用案例。 一、组件基础概念 1. 什么是组件? 组件是 Vue 应用的基本构建块,封装了 HTML、C…...
java面试场景问题
还在补充,这几天工作忙,闲了会把答案附上去,也欢迎各位大佬评论区讨论 1.不用分布式锁如何防重复提交 方法 1:基于唯一请求 ID(幂等 Token) 思路:前端生成 一个唯一的 requestId(…...
MySQL数据库基本概念
目录 什么是数据库 从软件角度出发 从网络角度出发 MySQL数据库的client端和sever端进程 mysql的client端进程连接sever端进程 mysql配置文件 MySql存储引擎 MySQL的sql语句的分类 数据库 库的操作 创建数据库 不同校验规则对查询的数据的影响 不区分大小写 区…...
【wiki知识库】07.用户管理后端SpringBoot部分
目录 一、今日目标 二、??SpringBoot部分类的添加 2.1 使用逆向工程新增User模块 2.2 UserQueryParam添加 2.3 UserSaveParam添加 2.4 UserResetPasswordParam添加 2.5 UserQueryVo添加 2.6 SnowFlake工具类 三、??后端新增接口? 3.1 /user/list接口添加 3.2 /…...
千峰React:案例二
完成对html文档还有css的引入,引入一下数据: import { func } from prop-types import ./购物车样式.css import axios from axios import { useImmer } from use-immer import { useEffect } from reactfunction Item() {return (<li classNameacti…...
Junit框架缺点
JUnit 是 Java 生态中最流行的单元测试框架,广泛应用于单元测试和集成测试中。尽管它功能强大且易于使用,但也存在一些缺陷和局限性。以下是 JUnit 的主要缺点: 1. 功能相对固定 问题:JUnit 的核心功能相对固定,缺乏灵…...
计算机毕业设计SpringBoot+Vue.js公司日常考勤系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
Python线程池知多少
目录 目标 Python版本 官方文档 概述 线程池 实战 创建线程池的基本语法 批量提交任务 生产者&消费者模型 目标 掌握线程池的基本概念和使用方法。 Python版本 Python 3.9.18 官方文档 concurrent.futures — Launching parallel taskshttps://docs.python.org/3…...
MySQL数据库入门到大蛇尚硅谷宋红康老师笔记 高级篇 part 6
从6到12章将会是重中之重,请一定好好看 第06章_索引的数据结构 1.为什么使用索引 索引是存储引擎用于快速找到数据记录的一种数据结构,就好比一本教课书的目录部分,通过目录中找到对应文章的页码,便可快速定位到需要的文章。MySQL中也是一…...
C++动态与静态转换区别详解
文章目录 前言一、 类型检查的时机二、安全性三、适用场景四、代码示例对比总结 前言 在 C 中,dynamic_cast 和 static_cast 是两种不同的类型转换操作符,主要区别体现在类型检查的时机、安全性和适用场景上。以下是它们的核心区别: 一、 类…...
面向AI 的前端发展及初识大模型
AI带来的开发范式迁移 随着AI的涌现,对前端的发展也有着非常大的影响,总结过去前端的发展路径,目前应该属于又一次的大规模的开发范式迁移阶段。上一个阶段是从jquery到React/Vue/Angular迁移(jquery之前的就不讨论了)…...
Java入门的基础学习
Java的基础语法知识 一 初始Java二 Java数据类型和变量1.字面常量2.数据类型基本数据类型引用数据类型 3.变量整型变量浮点型变量字符型变量布尔型变量 4.类型转化和提升类型转化类型提升 三 运算符1.算数运算符2.关系操作符3.逻辑运算符:&&,||&…...
万字详解 MySQL MGR 高可用集群搭建
文章目录 1、MGR 前置介绍 1.1、什么是 MGR1.2、MGR 优点1.3、MGR 缺点1.4、MGR 适用场景 2、MySQL MGR 搭建流程 2.1、环境准备2.2、搭建流程 2.2.1、配置系统环境2.2.2、安装 MySQL2.2.3、配置启动 MySQL2.2.4、修改密码、设置主从同步2.2.5、安装 MGR 插件 3、MySQL MGR 故…...
脚本无法获取响应主体(原因:CORS Missing Allow Credentials)
背景: 前端的端口号8080,后端8000。需在前端向后端传一个参数,让后端访问数据库去检测此参数是否出现过。涉及跨域请求,一直有这个bug是404文件找不到。 在修改过程当中不小心删除了一段代码,出现了这个bug࿰…...
GD32F450 使用
GB32F450使用 1. 相关知识2. 烧写程序3. SPI3.1 spi基础3.2 spi代码 4. 串口4.1 串口引脚4.2 串口通信代码 问题记录1. 修改晶振频率 注意:GD32F450 总共有三种封装形式,本文所述的相关代码和知识,均为 GD32F450IX 系列。 1. 相关知识 参数配…...
神经网络代码入门解析
神经网络代码入门解析 import torch import matplotlib.pyplot as pltimport randomdef create_data(w, b, data_num): # 数据生成x torch.normal(0, 1, (data_num, len(w)))y torch.matmul(x, w) b # 矩阵相乘再加bnoise torch.normal(0, 0.01, y.shape) # 为y添加噪声…...
Android 数据库查询对比(APN案例)
功能背景 APN 数据通常存储在数据库中,由TelephonyProvider提供。当用户进入APN设置界面时,Activity会启动,AOSP源码通过ContentResolver查询APN数据。关键分析点在于这个查询操作是否在主线程执行,因为主线程上的耗时操作会导致…...
神卓 S500 异地组网设备实现监控视频异地组网的详细步骤
一、设备与环境准备 硬件清单 主设备:神卓 S500 异地组网路由器 1子设备:神卓 S500 或兼容设备 N(需通过官网认证)监控设备:支持 RTSP/ONVIF 协议的 NVR、摄像头网络要求:各网点需稳定联网(推荐…...
golang安装(1.23.6)
1.切换到安装目录 cd /usr/local 2.下载安装包 wget https://go.dev/dl/go1.23.6.linux-amd64.tar.gz 3.解压安装包 sudo tar -C /usr/local -xzf go1.23.6.linux-amd64.tar.gz 4.配置环境变量 vi /etc/profile export PATH$…...
leetcode35.搜索插入位置
题目: 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出…...
LeetCode第57题_插入区间
LeetCode 第57题:插入区间 题目描述 给你一个 无重叠的 ,按照区间起始端点排序的区间列表。在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。 难度 中…...
人工智能之数学基础:线性代数中矩阵的运算
本文重点 矩阵的运算在解决线性方程组、描述线性变换等方面发挥着至关重要的作用。通过对矩阵进行各种运算,可以简化问题、揭示问题的本质特征。在实际应用中,我们可以利用矩阵运算来处理图像变换、数据分析、电路网络等问题。深入理解和掌握矩阵的运算,对于学习线性代数以…...
SQL Server 创建用户并授权
创建用户前需要有一个数据库,创建数据库命令如下: CREATE DATABASE [数据库名称]; CREATE DATABASE database1;一、创建登录用户 方式1:SQL命令 命令格式:CREATE LOGIN [用户名] WITH PASSWORD ‘密码’; 例如,创…...
MySQL双主搭建-5.7.35
文章目录 上传并安装MySQL 5.7.35双主复制的配置实例一:172.25.0.19:实例二:172.25.0.20: 配置复制用户在实例 1 (172.25.0.19)上执行:在实例 2 (172.25.0.20)上执行&…...
RNN实现精神分裂症患者诊断(pytorch)
RNN理论知识 RNN(Recurrent Neural Network,循环神经网络) 是一种 专门用于处理序列数据(如时间序列、文本、语音、视频等)的神经网络。与普通的前馈神经网络(如 MLP、CNN)不同,RNN…...
Python中字符串的常用操作
一、r原样输出 在 Python 中,字符串前加 r(即 r"string" 或 rstring)表示创建一个原始字符串(raw string)。下面详细介绍原始字符串的特点、使用场景及与普通字符串的对比。 特点 忽略转义字符࿱…...
uniapp 本地数据库多端适配实例(根据运行环境自动选择适配器)
项目有个需求,需要生成app和小程序,app支持离线数据库,如果当前没有网络提醒用户开启离线模式,所以就随便搞了下,具体的思路就是: 一个接口和多个实现类(类似后端的模板设计模式)&am…...
Spring Cloud Gateway 整合Spring Security
做了一个Spring Cloud项目,网关采用 Spring Cloud Gateway,想要用 Spring Security 进行权限校验,由于 Spring Cloud Gateway 采用 webflux ,所以平时用的 mvc 配置是无效的,本文实现了 webflu 下的登陆校验。 1. Sec…...
【异地访问本地DeepSeek】Flask+内网穿透,轻松实现本地DeepSeek的远程访问
写在前面:本博客仅作记录学习之用,部分图片来自网络,如需引用请注明出处,同时如有侵犯您的权益,请联系删除! 文章目录 前言依赖Flask构建本地网页访问LM Studio 开启网址访问DeepSeek 调用模板Flask 访问本…...
Windows对比MacOS
Windows对比MacOS 文章目录 Windows对比MacOS1-环境变量1-Windows添加环境变量示例步骤 1:打开环境变量设置窗口步骤 2:添加系统环境变量 2-Mac 系统添加环境变量示例步骤 1:打开终端步骤 2:编辑环境变量配置文件步骤 3࿱…...
React实现无缝滚动轮播图
实现效果: 由于是演示代码,我是直接写在了App.tsx里面在 文件位置如下: App.tsx代码如下: import { useState, useEffect, useCallback, useRef } from "react"; import { ImageContainer } from "./view/ImageC…...
Ubuntu20.04确认cuda和cudnn已经安装成功
当我们通过官网安装cuda和cudnn时,终端执行完命令后我们仍不能确定是否已经安装成功。接下来教大家用几句命令测试。 cuda 检测版本号 nvcc -V如果输出如下,则安装成功。 可以看到版本号是11.2 cudnn检测版本号 有两种命令:如果你的cudn…...
sqlilab 46 关(布尔、时间盲注)
sqlilabs 46关(布尔、时间盲注) 46关有变化了,需要我们输入sort,那我们就从sort1开始 递增测试: 发现测试到sort4就出现报错: 我们查看源码: 从图中可看出:用户输入的sort值被用于查…...
AI时代保护自己的隐私
人工智能最重要的就是数据,让我们面对现实,大多数人都不知道他们每天要向人工智能提供多少数据。你输入的每条聊天记录,你发出的每条语音命令,人工智能生成的每张图片、电子邮件和文本。我建设了一个网站(haptool.com),…...
模型优化之强化学习(RL)与监督微调(SFT)的区别和联系
强化学习(RL)与监督微调(SFT)是机器学习中两种重要的模型优化方法,它们在目标、数据依赖、应用场景及实现方式上既有联系又有区别。 想了解有关deepseek本地训练的内容可以看我的文章: 本地基于GGUF部署的…...
Buildroot 添加自定义模块-内置文件到文件系统
目录 概述实现步骤1. 创建包目录和文件结构2. 配置 Config.in3. 定义 cp_bin_files.mk4. 添加源文件install.shmy.conf 5. 配置与编译 概述 Buildroot 是一个高度可定制和模块化的嵌入式 Linux 构建系统,适用于从简单到复杂的各种嵌入式项目. buildroot的源码中bui…...
蓝牙接近开关模块感应开锁手机靠近解锁支持HID低功耗
ANS-BT101M是安朔科技推出的蓝牙接近开关模块,低功耗ble5.1,采用UART通信接口,实现手机自动无感连接,无需APP,人靠近车门自动开锁,支持苹果、安卓、鸿蒙系统,也可以通过手机手动开锁或上锁&…...
计算机毕业设计SpringBoot+Vue.js基于工程教育认证的计算机课程管理平台(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
企业知识库搭建:14款开源与免费系统选择
本文介绍了以下14 款知识库管理系统:1.Worktile;2.PingCode;3.石墨文档; 4. 语雀; 5. 有道云笔记; 6. Bitrix24; 7. Logseq等。 在如今的数字化时代,企业和团队面临着越来越多的信息…...
蓝桥杯(握手问题)
小蓝组织了一场算法交流会议,总共有 50 人参加了本次会议。在会议上,大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进行一次握手 (且仅有一次)。 但有 7个人,这 7 人彼此之间没有进行握手 (但这 7 人与除这 7 人以外…...
如何使用 Jenkins 实现 CI/CD 流水线:从零开始搭建自动化部署流程
如何使用 Jenkins 实现 CI/CD 流水线:从零开始搭建自动化部署流程 在软件开发过程中,持续集成(CI)和持续交付(CD)已经成为现代开发和运维的标准实践。随着代码的迭代越来越频繁,传统的手动部署方式不仅低效,而且容易出错。为了提高开发效率和代码质量,Jenkins作为一款…...
c++字符编码/乱码问题
基本概念 c11版本引入了char16_t和char32_t两个类型,他们的特点分别如下: char16_t 16位的unicode字符类型用于表示UTF-16编码大小:2字节字面量前缀:u char32_t 32位unicode字符类型用于表示UTF-32编码大小:4字节…...
侯捷 C++ 课程学习笔记:深入理解类与继承
文章目录 每日一句正能量一、课程背景二、学习内容:类与继承(一)类的基本概念1. 类的定义与实例化2. 构造函数与析构函数 (二)继承1. 单继承与多继承2. 虚函数与多态 三、学习心得四、总结 每日一句正能量 有种承担&am…...
初始化列表
一:声明,定义,赋值的区别 ①:声明 这里,int _year; int _month;int _day; 是成员变量的声明,它们告诉编译器: 类 Date中有三个成员变量_year和 _month和_day。 它们的类型分别都是 int 此…...
7.1 - 定时器之中断控制LED实验
文章目录 1 实验任务2 系统框图3 软件设计 1 实验任务 本实验任务是通过CPU私有定时器的中断,每 200ms 控制一次PS LED灯的亮灭。 2 系统框图 3 软件设计 注意事项: 定时器中断在收到中断后,只需清除中断状态,无需禁用中断、启…...
Pytest之fixture的常见用法
文章目录 1.前言2.使用fixture执行前置操作3.使用conftest共享fixture4.使用yield执行后置操作 1.前言 在pytest中,fixture是一个非常强大和灵活的功能,用于为测试函数提供固定的测试数据、测试环境或执行一些前置和后置操作等, 与setup和te…...