天天看點

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

           

繼續閱讀