备忘录模式
备忘录模式能记录一个对象的内部状态,当用户后悔时能撤销当前操作,使数据恢复到它原先的状态。比如操作word的时候的撤销功能,浏览器的回退功能,等等都可以采用备忘录来实现。
意图:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
备忘录模式是一种对象行为型模式,其主要优点如下。
- 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
- 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
- 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。
其主要缺点是:
- 资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。
完整代码如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace _17_Memento
{
class Program
{
/// <summary>
/// 备忘录模式
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
//备忘录是一种行为设计模式, 允许生成对象状态的快照并在以后将其还原。
Originator originator = new Originator("Super-duper-super-puper-super.");
Caretaker caretaker = new Caretaker(originator);
caretaker.Backup();
originator.DoSomething();
caretaker.Backup();
originator.DoSomething();
caretaker.Backup();
originator.DoSomething();
caretaker.Backup();
originator.DoSomething();
caretaker.Backup();
originator.DoSomething();
Console.WriteLine("\nClient: Now, let's rollback!\n");
caretaker.Undo();
Console.WriteLine("\n\nClient: Once more!\n");
caretaker.Undo();
Console.WriteLine();
Console.ReadKey();
}
}
class Originator
{
private string _state;
public Originator(string state)
{
_state = state;
Console.WriteLine("Originator:My initial state is:"+state);
}
public void DoSomething()
{
Console.WriteLine("Originator: I'm doing something important");
_state = GenerateRandomString(30);
Console.WriteLine($"Originator: and my state has changed to: {_state}");
}
private string GenerateRandomString(int length = 30)
{
string allowedSymbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
string result = string.Empty;
while (length > 0)
{
result += allowedSymbols[new Random().Next(0, allowedSymbols.Length)];
Thread.Sleep(12);
length--;
}
return result;
}
public IMemento Save()
{
return new ConcreteMemento(this._state);
}
public void Restore(IMemento memento)
{
if(!(memento is ConcreteMemento))
{
throw new Exception("Unknown memento class " + memento.ToString());
}
_state = memento.GetState();
Console.Write($"Originator: My state has changed to: {_state}");
}
}
public interface IMemento
{
string GetName();
string GetState();
DateTime GetDate();
}
class ConcreteMemento : IMemento
{
private string _state;
private DateTime _date;
public ConcreteMemento(string state)
{
_state = state;
_date = DateTime.Now;
}
public string GetState()
{
return _state;
}
public string GetName()
{
return $"{_date} / ({_state.Substring(0, 9)})...";
}
public DateTime GetDate()
{
return _date;
}
}
class Caretaker
{
private List<IMemento> _mementos = new List<IMemento>();
private Originator _originator = null;
public Caretaker(Originator originator)
{
_originator = originator;
}
public void Backup()
{
Console.WriteLine("\nCaretaker: Saving Originator's state...");
_mementos.Add(_originator.Save());
}
public void Undo()
{
if(_mementos.Count == 0)
{
return;
}
var memento = _mementos.Last();
_mementos.Remove(memento);
Console.WriteLine("Caretaker: Restoring state to: " + memento.GetName());
try
{
_originator.Restore(memento);
}
catch (Exception)
{
Undo();
}
}
public void ShowHistory()
{
Console.WriteLine("Caretaker: Here's the list of mementos:");
foreach (var memento in _mementos)
{
Console.WriteLine(memento.GetName());
}
}
}
}