天天看点

17.备忘录模式(Memento Pattern)

备忘录模式

备忘录模式能记录一个对象的内部状态,当用户后悔时能撤销当前操作,使数据恢复到它原先的状态。比如操作word的时候的撤销功能,浏览器的回退功能,等等都可以采用备忘录来实现。

意图:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

备忘录模式是一种对象行为型模式,其主要优点如下。

  • 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
  • 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
  • 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。

其主要缺点是:

  • 资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。
17.备忘录模式(Memento Pattern)

完整代码如下

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());
            }
        }
    }
}