本文作者:小黑黑

[设计模式]行为型模式之备忘录模式

小黑黑 1年前 ( 2019-03-04 ) 1036 抢沙发
[设计模式]行为型模式之备忘录模式摘要: 一、引言        备忘录模式,我们从字面的意思来理解的话,就是对某个类的状态进行保存下来,等到需要恢复的时候,可以...

一、引言

        备忘录模式,我们从字面的意思来理解的话,就是对某个类的状态进行保存下来,等到需要恢复的时候,可以从备忘录中进行恢复。我们以前应该都玩过魂斗罗的游戏,当你过了一关之后或我们死亡之前都可以将游戏进行存档,等到我们在想回到这关的时候,我们只需要重新读档就可以,这就是备忘录模式,常见的备忘录模式还有:备忘手机通讯录,备份数据库,备份操作系统等。

二、动机

        在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个节点时的状态。如果使用一些公有接口来让其他对象得到对象的状态,便会暴露对象的细节实现。如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的封装性。

三、意图

        在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。            --《设计模式》 GoF

四、结构

123.PNG

4.1  模式的组成

        1、发起人角色(Originator):记录当前时刻的内部状态,负责创建和恢复备忘录数据。

        2、备忘录角色(Memento):负责存储发起人对象的内部状态,在进行恢复时提供给发起人需要的状态,并可以防止发起人角色以外的其他对象访问备忘录。

        3、管理者角色(Caretaker):负责保存备忘录角色。

五、备忘录模式的具体实现

        下面我们将以魂斗罗游戏为例,使用代码来看看备忘录模式是怎样实现的:

    /// <summary>
    /// 魂斗罗游戏,相当于发发起人
    public class Contra
    {

        /// <summary>
        /// 关数
        /// </summary>
        public int CheckPoint { get; set; }

        /// <summary>
        /// 使用枪械的名称
        /// </summary>
        public string Gun { get; set; }

        /// <summary>
        /// 血量
        /// </summary>
        public int HP { get; set; }

        /// <summary>
        /// 打印信息
        /// </summary>
        public void Show()
        {
            Console.WriteLine($"当前第 {CheckPoint} 关,使用 {Gun}, 血量 {HP}%");
        }

        /// <summary>
        /// 保存关卡
        /// </summary>
        /// <param name="name">关卡名称</param>
        public void Save(string name)
        {
            ContraMemento memento = new ContraMemento(CheckPoint, Gun, HP);
            ContraCaretaker.SaveMemento(name, memento);
        }

        /// <summary>
        /// 重新加载关卡
        /// </summary>
        /// <param name="name">关卡名称</param>
        public void Load(string name)
        {
            ContraMemento memento = ContraCaretaker.LoadMemento(name);
            this.CheckPoint = memento.CheckPoint;
            this.Gun = memento.Gun;
            this.HP = memento.HP;
        }
    }
    
    /// <summary>
    /// 魂斗罗游戏备忘录角色
    /// </summary>
    public class ContraMemento
    {

        /// <summary>
        /// 关数
        /// </summary>
        public int CheckPoint { get; set; }

        /// <summary>
        /// 使用枪械的名称
        /// </summary>
        public string Gun { get; set; }

        /// <summary>
        /// 血量
        /// </summary>
        public int HP { get; set; }

        public ContraMemento(int checkPoint, string gun, int hp)
        {
            this.CheckPoint = checkPoint;
            this.Gun = gun;
            this.HP = hp;
        }
    }
    
    /// <summary>
    /// 备忘录管理角色
    /// </summary>
    public class ContraCaretaker
    {

        private static Dictionary<string, ContraMemento> mementoDictionary = new Dictionary<string, ContraMemento>();

        /// <summary>
        /// 保存备忘录
        /// </summary>
        public static void SaveMemento(string name, ContraMemento memento)
        {
            if (!mementoDictionary.ContainsKey(name))
            {
                mementoDictionary.Add(name, memento);
            }
            else
            {
                throw new Exception("关卡名称已存在,请重新输入");
            }
        }

        /// <summary>
        /// 重新加载关卡
        /// </summary>
        public static ContraMemento LoadMemento(string name)
        {
            if (mementoDictionary.ContainsKey(name))
            {
                return mementoDictionary[name];
            }
            else
            {
                throw new Exception("关卡不存在");
            }
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Contra contra = new Contra()
            {
                CheckPoint = 1,
                Gun = "普通枪",
                HP = 100
            };

            //先保存一下
            contra.Save("游戏开始");
            contra.Show();

            contra.CheckPoint = 2;
            contra.Gun = "激光枪";
            contra.HP = 80;

            //保存一下
            contra.Save("第二关");
            contra.Show();


            contra.CheckPoint = 3;
            contra.Gun = "激光枪";
            contra.HP = 60;

            //保存一下
            contra.Save("第三关");
            contra.Show();

            //如果想恢复到第一关
            contra.Load("第二关");
            contra.Show();

            Console.Read();
        }
    }

六、备忘录模式的优缺点

优点:

        1、如果某个操作错误地破坏了数据的完整性,此时可以使用备忘录模式将数据恢复至原来的状态。

        2、备份的状态数据保存在发起人角色之外,这样发起人角色就不要对各个备份的状态进行管理。而是由备忘录角色来进行管理,而备忘录角色又由管理者角色管理,符合单一职责原则。

缺点:

        1、在实际的系统中,可能需要维护多个备份,需要额外的资源,这样对资源的消耗比较严重。

分享到: 网站分享代码

发表评论

快捷回复:

评论列表 (暂无评论,1036人围观)参与讨论

还没有评论,来说两句吧...