设计模式Python版 备忘录模式

news/2025/2/27 6:04:43

文章目录


前言

GOF设计模式分三大类:

  • 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。
  • 结构型模式:关注类和对象之间的组合,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。
  • 行为型模式:关注对象之间的交互,包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。

一、备忘录模式

备忘录模式(Memento Pattern)

  • 定义:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。

  • 解决问题:如何在软件中实现撤销功能?

  • 使用场景:

    • 保存一个对象在某一个时刻的全部状态或部分状态,这样以后需要时就能够恢复到先前的状态,实现撤销操作。
    • 防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态的实现细节暴露给外界对象。
  • 组成:

    • Originator(原发器):它是一个普通类,可以创建一个备忘录,并存储其当前内部状态,也可以使用备忘录来恢复其内部状态。一般将需要保存内部状态的类设计为原发器。
    • Memento(备忘录):存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用。
    • Caretaker(负责人):负责人又称为管理者,他负责保存备忘录,但是不能对备忘录的内容进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,他只负责存储对象,而不能修改对象,也无须知道对象的实现细节。
  • 补充说明:

    • 撤销功能的实现原理:在实现撤销时,首先必须保存软件系统的历史状态。当用户需要取消错误操作并且返回到某个历史状态时,可以取出事先保存的历史状态来覆盖当前状态。
    • 通过使用备忘录模式可以使系统恢复到某一特定的历史状态。当前很多软件都提供了撤销(Undo)操作,其中就使用了备忘录模式
    • 备忘录模式的核心是备忘录类以及用于管理备忘录的负责人类的设计。
      • 在真实业务中,原发器类是一个具体的业务类,它包含一些用于存储成员数据的属性。
      • 对于备忘录类Memento而言,它通常提供了与原发器相对应的属性(可以是全部,也可以是部分)用于存储原发器的状态。
      • 对于负责人类Caretaker,它用于保存备忘录对象,并提供getMemento()方法用于向客户端返回一个备忘录对象。
  • 优点:

    • 它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤。
    • 备忘录实现了对信息的封装。
  • 缺点:

    • 资源消耗过大

在这里插入图片描述

二、备忘录模式示例1

使用备忘录模式来设计中国象棋软件,提供“悔棋”功能

  • Chessman充当原发器,ChessmanMemento充当备忘录,MementoCaretaker充当负责人
  • 在MementoCaretaker中定义了一个ChessmanMemento类型的对象,用于存储备忘录。
python">### 备忘录模式
"""原发器:象棋棋子"""


class Chessman:
    def __init__(self, label: str, x: int, y: int):
        self.label = label
        self.x = x
        self.y = y

    def save(self) -> "ChessmanMemento":
        # 保存状态
        return ChessmanMemento(self.label, self.x, self.y)

    def restore(self, memento: "ChessmanMemento"):
        # 恢复状态
        self.label = memento.label
        self.x = memento.x
        self.y = memento.y


"""备忘录:象棋棋子备忘录"""


class ChessmanMemento:
    def __init__(self, label: str, x: int, y: int):
        self.label = label
        self.x = x
        self.y = y


"""负责人:象棋棋子备忘录管理"""


class MementoCaretaker:
    def __init__(self):
        self.memento: ChessmanMemento = None

    def get_memento(self):
        return self.memento

    def set_memento(self, memento: ChessmanMemento):
        self.memento = memento
  • 客户端代码
python">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 = 4
    display(chess)
    mc.set_memento(chess.save())  # 保存状态

    chess.x = 5
    display(chess)
    print("###悔棋###")
    chess.restore(mc.get_memento())  # 恢复状态
    display(chess)
  • 输出结果
棋子 车 当前位置为:行 22
棋子 车 当前位置为:行 24
棋子 车 当前位置为:行 54
###悔棋###
棋子 车 当前位置为:行 24

三、备忘录模式示例2

实现多次撤销

  • 在负责人类中定义列表来存储多个备忘录。修改负责人代码:
python">"""负责人:象棋棋子备忘录管理"""
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 memento

    def set_memento(self, memento: ChessmanMemento):
        # 下棋保存状态
        self.memento_list_b.clear()  # 棋子前进,则清空悔棋状态
        self.memento_list_f.append(memento)
  • 客户端代码
python">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 = 4
    play(chess, mc)
    chess.x = 5
    play(chess, mc)
    undo(chess, mc)
    undo(chess, mc)
    redo(chess, mc)
    redo(chess, mc)
  • 输出结果
棋子 车 当前位置为:行 11
棋子 车 当前位置为:行 14
棋子 车 当前位置为:行 54
###悔棋###
棋子 车 当前位置为:行 14
###悔棋###
棋子 车 当前位置为:行 11
###撤销悔棋###
棋子 车 当前位置为:行 14
###撤销悔棋###
棋子 车 当前位置为:行 54

您正在阅读的是《设计模式Python版》专栏!关注不迷路~


http://www.niftyadmin.cn/n/5869604.html

相关文章

神经网络 - 函数饱和性、软性门、泰勒级数

在接下来对于神经网络的学习中,我们会涉及到函数饱和性、软性门的概念,还需要用到泰勒级数,本文我们来理解这些基础知识,为后续学习神经网络的激活函数做准备。 一、函数饱和性 “函数具有饱和性”通常指的是当函数的输入达到某…

算法题(79):两个数组的交集

审题: 本题需要我们查找两个给定数组的无重复数据交集,并以数组的形式返回 思路: 方法一:set 之前我们学习过unordered_set的使用,但是unordered_set是无序的,而这里我们的比对算法需要有序数据&#xff0c…

MATLAB基础应用精讲-【数模应用】牛顿迭代法(附MATLAB、C++、R语言和python代码实现)

目录 前言 算法原理 什么是牛顿迭代法? 牛顿迭代如何迭代? 啥时候停止迭代呢? 特点 牛顿迭代法的扩展 迭代过程 数学模型 电力系统中牛顿拉夫逊法(N-R)潮流计算的直角坐标形式详细推导 潮流计算的牛顿-拉夫逊方法 牛顿-拉夫逊法的原理 牛顿-拉夫逊法的意义和…

Linux系统之DHCP网络协议

目录 一、DHCP概述 二、DHCP部署实操 2.1、安装DHCP软件 2.2、拷贝配置文件 2.3、配置文件详解 2.4、重启软件服务 2.5、新开一台服务器,查看dhcp地址获取 一、DHCP概述 DHCP(Dynamic Host Configuration Protocol)是一种应用层网络协…

一周学会Flask3 Python Web开发-Jinja2模版中加载静态文件

锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 一个Web项目不仅需要HTML模板,还需要许多静态文件,比如 CSS、JavaScript文件、图片以及音频等。在Fla…

【K8S】Kubernetes 中的基本组成部分介绍,一文了解 K8S 中的所有概念

应用 (Application) 定义:应用是业务逻辑的实现,非 K8S 中的官方的概念,但容器中运行的实际程序通常就被认为是应用层级关系:Application ∈ Container。Pod 是运行应用的载体,应用通是和容器一一对应,多个…

2011-2019年各省乡镇综合文化站机构数数据

2011-2019年各省乡镇综合文化站机构数数据 1、时间:2011-2019年 2、来源:国家统计局、统计年鉴 3、指标:行政区划代码、地区、年份、乡镇综合文化站机构数 4、范围:31省 5、指标解释:乡镇综合文化站是中国基层文化…

Windows 11【1001问】修改主题隐藏或删除Win11桌面“了解此图片”

在<Windows 11【1001问】如何安装Windows 11>篇幅中我们第一安装完成Windows 11还未开始其他操作的时候会发现桌面上有一个“了解此图片”的图标是之前没见过的&#xff1b;而在Windows 11中&#xff0c;“了解此图片”图标是微软引入的一项功能&#xff0c;旨在让用户通…