備忘錄模式
備忘錄模式能記錄一個對象的内部狀态,當使用者後悔時能撤銷目前操作,使資料恢複到它原先的狀态。比如操作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());
}
}
}
}