备忘录模式属于行为型设计模式,核心能力是在不暴露对象内部细节的情况下,保存对象的某一时刻状态,后续可以根据需求将对象恢复到对应状态。在C#的实际开发中,这种模式常被用于实现撤销、回滚、历史记录回溯等功能。

备忘录模式的核心角色
备忘录模式的实现通常包含三个核心角色,每个角色有明确的职责划分:
- 原发器(Originator):需要保存状态的对象,负责创建备忘录存储自己的状态,也可以通过备忘录恢复自身状态。
- 备忘录(Memento):存储原发器的内部状态,通常只暴露给原发器访问,对其他对象隐藏状态细节。
- 负责人(Caretaker):负责保存备忘录对象,但是不能对备忘录的内容进行操作或者修改。
基础实现示例
下面先通过一个简单的文本编辑器状态保存的场景,展示备忘录模式的基础实现逻辑:
// 原发器:文本编辑器
public class TextEditor
{
// 当前编辑的文本内容
public string Content { get; set; }
// 创建备忘录,保存当前状态
public EditorMemento CreateMemento()
{
return new EditorMemento(Content);
}
// 从备忘录恢复状态
public void RestoreFromMemento(EditorMemento memento)
{
Content = memento.SavedContent;
}
}
// 备忘录:存储编辑器状态
public class EditorMemento
{
// 保存的内容,只对原发器开放访问
public string SavedContent { get; private set; }
public EditorMemento(string content)
{
SavedContent = content;
}
}
// 负责人:管理备忘录
public class HistoryManager
{
private List<EditorMemento> _mementos = new List<EditorMemento>();
// 添加备忘录
public void AddMemento(EditorMemento memento)
{
_mementos.Add(memento);
}
// 获取指定索引的备忘录
public EditorMemento GetMemento(int index)
{
if (index >= 0 && index < _mementos.Count)
{
return _mementos[index];
}
return null;
}
}
上述是基础实现,但是实际开发中经常会遇到状态包含引用类型的情况,基础实现的对象拷贝是浅拷贝,修改恢复后的状态可能会影响备忘录存储的内容,这就需要进阶的深拷贝处理。
进阶实现:处理引用类型状态
当原发器的状态包含引用类型(比如自定义类、集合等)时,需要实现深拷贝来保证备忘录存储的状态和原发器当前状态完全独立。下面以包含附件列表的文档编辑器为例:
// 附件类,引用类型
public class Attachment
{
public string FileName { get; set; }
public byte[] FileData { get; set; }
// 实现深拷贝的方法
public Attachment DeepCopy()
{
return new Attachment
{
FileName = this.FileName,
// 数组拷贝,避免引用同一个数组对象
FileData = this.FileData == null ? null : this.FileData.ToArray()
};
}
}
// 进阶原发器:带附件的文档编辑器
public class DocumentEditor
{
public string Title { get; set; }
public string Content { get; set; }
public List<Attachment> Attachments { get; set; } = new List<Attachment>();
// 创建深拷贝的备忘录
public DocumentMemento CreateMemento()
{
// 对附件列表做深拷贝
var copiedAttachments = new List<Attachment>();
foreach (var attachment in Attachments)
{
copiedAttachments.Add(attachment.DeepCopy());
}
return new DocumentMemento(Title, Content, copiedAttachments);
}
// 从备忘录恢复状态
public void RestoreFromMemento(DocumentMemento memento)
{
Title = memento.SavedTitle;
Content = memento.SavedContent;
// 恢复时也对附件做深拷贝,避免后续修改影响备忘录
Attachments = new List<Attachment>();
foreach (var attachment in memento.SavedAttachments)
{
Attachments.Add(attachment.DeepCopy());
}
}
}
// 进阶备忘录:存储文档状态
public class DocumentMemento
{
public string SavedTitle { get; }
public string SavedContent { get; }
public List<Attachment> SavedAttachments { get; }
public DocumentMemento(string title, string content, List<Attachment> attachments)
{
SavedTitle = title;
SavedContent = content;
// 存储时已经做了深拷贝,这里直接赋值即可
SavedAttachments = attachments;
}
}
进阶优化:备忘录存储管理
当备忘录数量较多时,负责人需要优化存储策略,避免占用过多内存。可以结合业务场景设置存储上限,或者将旧的备忘录持久化到本地文件、数据库:
public class OptimizedHistoryManager
{
// 最大存储备忘录数量
private readonly int _maxMementoCount;
private List<DocumentMemento> _mementos = new List<DocumentMemento>();
public OptimizedHistoryManager(int maxMementoCount = 10)
{
_maxMementoCount = maxMementoCount;
}
public void AddMemento(DocumentMemento memento)
{
_mementos.Add(memento);
// 超过上限时移除最早的备忘录
if (_mementos.Count > _maxMementoCount)
{
_mementos.RemoveAt(0);
}
}
// 持久化备忘录到本地文件
public void PersistMemento(int index, string filePath)
{
var memento = _mementos[index];
// 这里简化为序列化存储逻辑,实际可使用Json、二进制序列化等方式
var content = $"Title:{memento.SavedTitle},Content:{memento.SavedContent},AttachmentCount:{memento.SavedAttachments.Count}";
File.WriteAllText(filePath, content);
}
public DocumentMemento GetMemento(int index)
{
if (index >= 0 && index < _mementos.Count)
{
return _mementos[index];
}
return null;
}
}
使用注意事项
在使用C#实现备忘录模式时,需要注意以下几点:
- 如果原发器的状态数据量非常大,频繁创建备忘录会带来较大的内存开销,需要结合业务评估是否需要使用。
- 备忘录的访问权限要做好控制,通常只允许原发器访问备忘录的内部状态,其他对象只能传递备忘录,不能修改其内容。
- 如果状态包含大量引用类型,必须做好深拷贝处理,否则会出现状态互相影响的问题。
适用场景总结
备忘录模式适合以下场景:
- 需要保存对象的某个时刻状态,并且后续可能需要恢复到该状态。
- 需要实现撤销、重做功能,比如编辑器、绘图工具等。
- 需要记录操作历史,方便用户回溯之前的版本。
备忘录模式的核心优势是保持了对象的封装性,不会暴露对象的内部实现细节,但是需要根据状态复杂度做好性能和内存的平衡。
C#Memento_Pattern备忘录模式设计模式修改时间:2026-07-01 04:45:38