我们来用Unity的形式讲一下备忘录模式
 
你可以把备忘录模式想象成游戏中的“存档”和“读档”功能。 它的核心思想是: 再不破坏对象封装性的前提下, 捕获一个对象的内部状态, 并在该对象之外保存这个状态, 以便日后可以将对象恢复到原先保存的状态.
 

举个具体场景: 游戏角色状态保存与恢复

假设你正在开发一款RPG游戏, 玩家控制角色有以下状态:
  • 生命值(Health)
  • 魔法值(Mana)
  • 位置(Position)
  • 当前装备(Equipment)
 
当玩家进入一个危险的地牢前, 他可能会想”存档”. 如果在地牢里不幸死亡, 它可以”读档”回到进入地牢前的状态, 而不是从头开始.
 
在这个场景中, 我们可以使用备忘录模式来实现这个功能:
  1. 角色(Player)是哪个需要被”存档”的对象, 它知道如何创建一个包含自己当前状态的”备忘录”, 也知道如何从”备忘录”中恢复自己的状态.
  1. 游戏存档(GameSave)就是”备忘录”, 它是一个简单的数据容器, 用来存储角色状态(生命值\魔法值等). 它不包含任何游戏逻辑.
  1. 存档管理器(SaveManager)负责管理所有的”备忘录”. 它可以保存新的存档, 也可以根据需要取出一个旧的存档共角色恢复.
 

备忘录模式的核心角色

    1. 是谁? 在我们的例子中是 Player 脚本
    2. 作用是什么?
      1. 创建备忘录: 它可以在某个时刻, 将自己的内部状态(如生命值\位置)打包成一个备忘录对象
      2. 恢复状态: 它可以从一个备忘录对象中, 恢复自己的内部状态
    3. 关键特点: 它拥有自己的状态, 但它不负责存储这些状态的历史, 这个工作交给了负责人.
    1. 是谁? 在我们的例子中是 GameSave
    2. 作用是什么?
      1. 存储状态: 它是一个用来存储发起人内部状态的数据容器
      2. 保护状态: 它应该只允许发起人访问它的内部数据. 其他对象不应该能够读取或修改它
    3. 关键特点: 它通常是一个简单的\可序列化的类, 只包含数据字段和相应的gettrt/setter方法(或者在某些实现中, setter 是私有的, 只能由发起人调用).
    1. 是谁? 在我们例子中是 SaveManager 脚本
    2. 作用是什么?
      1. 管理备忘录: 它负责保存一系列备忘录对象, 可以把它想象成一个”存档列表”
      2. 提供访问: 当需要时, 它可以将一个特定的备忘录对象返回给发起人, 以便发起人进行状态恢复.
    3. 关键特点: 它不知道备忘录对象内部存储的具体细节. 它只负责”保管”备忘录, 而不”使用”它. 它与备忘录之间是一种聚合关系.
 

代码实现步骤

  1. 定义备忘录(Memento) - GameSave.cs
这是一个纯数据类, 用于存储角色的状态. 为了模式”只有发起人能访问”, 我们可以把 SetState 方法设为 internal 或通过狗在函数来初始化. 在C#中, 一个常见的作法是把备忘录类嵌套在发起人内部, 或者使用访问修饰符来控制. 这里我们为了清晰, 采用独立的类, 并通过构造一次性设置所有状态.
 
 
  1. 定义发起人(Originator) - Player.cs
这个类包含了角色当前状态和行为. 它负责创建和恢复备忘录.
 
  1. 定义负责人(Caretaker) - SaveManager.cs
这个类负责管理所有的游戏存档
 
  1. 客户端使用 - GameManager.cs
这是一个简单的游戏管理器, 用于演示整个流程
 

在 Unity 编辑器中配置

  1. 创建一个玩家对象(PLayer), 并添加 Player.cs 脚本
  1. 创建一个空对象作为 GameManager , 并添加 GameManager.cs 脚本.
  1. 在场景中创建另一个空对象, 命名为 SaveManager 并添加, SaveManager.cs 脚本
  1. GameManager 的 Inspector 面板中, 将 Player 对象和 SaveManager 对象拖到对应字段上.
  1. 运行游戏,在游戏视图中按以下按键进行测试:
      • S:创建一个名为 "BeforeDungeon" 的存档。
      • D:让玩家受到伤害。
      • F:让玩家施放法术,消耗魔法。
      • L:加载 "BeforeDungeon" 存档,玩家的生命值、魔法值和位置将恢复到存档时的状态。
 

备忘录模式的核心优势

  1. 状态保存与恢复: 这是最直接的好处, 允许对象在不同时间点之间切换状态, 非常适合实现”撤销/重做”或”存档/读档”功能.
  1. 封装性: 发起人(Player)的内部状态被封装在备忘录(GameSave)中, 并且只有发起人自己能够创建和恢复这个状态. 负责人(SaveManager)和其它对象无法访问或修改发起人内部的细节, 复合”封装变化”的原则.
  1. 简化发起人: 发起人不需要自己管理和维护状态的历史记录, 这个责任被移交给了负责人, 使得发起人代码更加简洁.
 

在Unity中的其他应用场景

  • 编辑器工具: 自定义编辑器窗口中, 对复杂配置的操作进行”撤销/重做”.
  • 动画系统: 保存和恢复动画状态机的某个特定状态
  • AI 行为: 在某些决策点保存AI的当前状态, 以便在特定条件下会输到之前的决策.
 
总结: 备忘录模式通过将对象状态的保存和恢复责任分离, 实现了对象状态的灵活管理, 同时保持了对象的封装性. 它就像一个可靠的”时光机”, 让对象可以在不同的状态之间自由穿梭