备忘录模式
本篇博客将介绍备忘录模式,备忘录模式是软件系统中的“月光宝盒”,它提供了一种对象状态的撤销实现机制,当系统中一个对象需要恢复某一个历史状态时,就可以使用备忘录模式进行设计。
模式分类
行为型设计模式。
模式产生的原因
在使用软件的过程中大家难免会产生一些误操作,例如不小心删除了某些文字或者图片,为了使软件更加人性化,对于这些误操作,需要提供一种类似于后悔药的机制,让软件系统可以回到误操作之前的状态,因此需要保存用户每一次操作时系统的状态,一旦出现误操作,只需要将存储的历史状态取出即可回到之前的状态。备忘录模式正是为此类问题而生的。
模式类图
由上图可知,备忘录模式有以下3个对象构成:
Originator(原发器):
原发器是一个普通类,一般我们会让需要备份的类作为原发器存在,原发器可以通过创建一个备忘录来保存当前的系统状态,也可以使用备忘录来恢复其内部状态。
Memento(备忘录):
备忘录用于存储原发器的内部状态,通常备忘录的设计会参考原发器的设计。需要注意的是除过Caretaker类和Originator类之外,系统其他类不可以访问备忘录的内容。
Caretaker(负责人类):
负责人类负责管理系统的备忘录。
代码实现
我们通过备忘录模式模拟word的撤销和重做功能。
NotePad原发器:
using System;
namespace Memento.Memento.Question5
{
public class NotePad
{
private string _content;
public void ChangeContent(string content)
{
_content = content;
SaveContent(content);
Show();
}
public void UndoContent()
{
_content = Caretaker.GetInstance.UndoPop().GetContent();
Show();
}
public void RedoContent()
{
_content = Caretaker.GetInstance.RedoPop().GetContent();
Show();
}
public void Show()
{
Console.WriteLine(_content);
}
private void SaveContent(string content)
{
Caretaker.GetInstance.UndoPush(new Memento(content));
}
}
}
Memento备忘录:
namespace Memento.Memento.Question5
{
public class Memento
{
private string _content;
public Memento(string content)
{
_content = content;
}
public void SetContent(string content)
{
_content = content;
}
public string GetContent()
{
return _content;
}
}
}
Caretaker负责人类:
using System;
using System.Collections.Generic;
namespace Memento.Memento.Question5
{
public class Caretaker
{
private static Caretaker _instance;
public static Caretaker GetInstance
{
get
{
if (_instance == null)
{
_instance = new Caretaker();
}
return _instance;
}
}
private Stack<Memento> _undoStack = new Stack<Memento>();
private Stack<Memento> _redoStack = new Stack<Memento>();
public void UndoPush(Memento memento)
{
_undoStack.Push(memento);
}
public Memento UndoPop()
{
if (_undoStack.Count == 0)
{
Console.WriteLine($"无法继续撤销");
}
Memento memento = _undoStack.Pop();
RedoPush(memento);
return memento;
}
public void RedoPush(Memento memento)
{
_redoStack.Push(memento);
}
public Memento RedoPop()
{
if (_redoStack.Count == 0)
{
Console.WriteLine($"无法继续重做");
}
Memento memento = _redoStack.Pop();
UndoPush(memento);
return memento;
}
}
}
Program类:
using System;
using Memento.Memento.Question5;
namespace Memento
{
internal class Program
{
public static void Main(string[] args)
{
NotePad notePad = new NotePad();
notePad.ChangeContent("123");
notePad.ChangeContent("1234");
notePad.UndoContent();
notePad.UndoContent();
notePad.RedoContent();
notePad.RedoContent();
notePad.ChangeContent("12345");
notePad.ChangeContent("123456");
notePad.UndoContent();
notePad.UndoContent();
notePad.ChangeContent("1234567");
notePad.ChangeContent("12345678");
notePad.UndoContent();
notePad.UndoContent();
notePad.UndoContent();
notePad.UndoContent();
}
}
}
原理是这么一个原理,但上述实现是有一点小问题的,每次重做或者撤销的时候,其顶层存放的就是当前状态。
备忘录模式总结
备忘录模式的优点:
- 备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便的回到一个特定的历史状态。
- 备忘录模式实现了对信息的封装,一个备忘录对象是一种原发器对象的状态表示,不会被其他代码所改动,一般在C#中为了实现这点我们通常会通过程序集进行区分。
备忘录模式的缺点:
- 经典备忘录模式的计算机资源消耗较大。