【手写源码-设计模式19】-备忘录模式-如果王者荣耀中有月光宝盒

1:主题拆解

①基本介绍

②如果王者荣耀中有月光宝盒

③备忘录模式的优缺点

④适用场景

⑤应用实例

⑥总结

2:基本介绍

【手写源码-设计模式19】-备忘录模式-如果王者荣耀中有月光宝盒_第1张图片

        备忘录模式:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。 

        备忘录模式保存的是我们关心的在恢复时需要的对象的部分状态信息,相当于快照。比如在玩游戏的时候有一个保存当前闯关的状态的功能,会对当前用户所处的状态进行保存,当用户闯关失败或者需要从快照的地方开始的时候,就能读取当时保存的状态完整地恢复到当时的环境,这一点和VMware上面的快照功能很类似。

3:如果王者荣耀中有月光宝盒

【手写源码-设计模式19】-备忘录模式-如果王者荣耀中有月光宝盒_第2张图片

         在王者荣耀中,对时间点的把握非常重要,把握好之后就会赢得比赛先机,不管是拿buff还是抢暴君和主宰,都会快敌人一步,从而掌握更多的资源,获取更大的经济优势,轻轻松松获得比赛的胜利。游戏中有最重要的四个时间点,掌握好之后至少提升两个段位!

        这四个时间节点依次为 第一波野怪,第一条暴君,第一条暗影主宰,第一条黑暗暴君。

        如果某一天王者荣耀添加一个道具月光宝盒,可以再随时返回到游戏的某个节点,重新弥补进度中的失误。似乎是一个很好玩的脑洞,哈哈。

        废话不多说,开始撸码

1:打脸版

①游戏英雄类

public class KingsGlory
{
    public string Hero { get; set; }
    public int Level { get; set; }
    public string Army { get; set; }
    public string Economic { get; set; }


    public void Show()
    {
        Console.WriteLine("********************************");
        Console.WriteLine("     Hero:{0}", this.Hero);
        Console.WriteLine("     Level:{0}级", this.Level);
        Console.WriteLine("     Army:{0}", this.Army);
        Console.WriteLine("     Economic:{0}", this.Economic);
        Console.WriteLine("********************************");
    }
}

②游戏开始

List listKingsGlory = new List();
KingsGlory kingsGlory = new KingsGlory()
{
    Hero = "甄姬-游梦惊园",
    Level = 1,
    Army = "法师*3 小兵*2",
    Economic = "200"
};
listKingsGlory.Add(kingsGlory);
kingsGlory.Show();
Console.WriteLine("*****第一波野怪*******");
kingsGlory.Level = 3;
kingsGlory.Army = "法师*3 小兵*2";
kingsGlory.Economic = "1K";

listKingsGlory.Add(kingsGlory);
kingsGlory.Show();

Console.WriteLine("********月光宝盒**********");
kingsGlory = listKingsGlory[0];
kingsGlory.Show();

分析:想象美好,现实打脸。这里的kingsGlory是引用类型,在经过后面的赋值之后,实际上对象已经变化了,没有保存,也没法回归到前面的进度。

2:重生一次

①添加备忘录类

public class KingsGloryMemento
{
    public int Level { get; private set; }
    public string Army { get; private set; }
    public string Economic { get; private set; }


    public KingsGloryMemento(int level, string army, string economic)
    {
        this.Level = level;
        this.Army = army;
        this.Economic = economic;
    }
}

②进度容器

public class Caretaker
{
    private static KingsGloryMemento _KingsGloryMemento = null;
    public static void SaveKingsGloryMemento(KingsGloryMemento kingsGloryMemento)
    {
        _KingsGloryMemento = kingsGloryMemento;
    }
    public static KingsGloryMemento GetKingsGloryMemento()
    {
        return _KingsGloryMemento;
    }
}

③英雄类添加职责

public class KingsGlory
{
    public string Hero { get; set; }
    public int Level { get; set; }
    public string Army { get; set; }
    public string Economic { get; set; }

    public void Show()
    {
        Console.WriteLine("********************************");
        Console.WriteLine("     Hero:{0}", this.Hero);
        Console.WriteLine("     Level:{0}级", this.Level);
        Console.WriteLine("     Army:{0}", this.Army);
        Console.WriteLine("     Economic:{0}", this.Economic);
        Console.WriteLine("********************************");
    }

    public void Save()
    {
        KingsGloryMemento memento = new KingsGloryMemento(this.Level, this.Army, this.Economic);
        Caretaker.SaveKingsGloryMemento(memento);
    }

    public void Load()
    {
        KingsGloryMemento memento = Caretaker.GetKingsGloryMemento();


        this.Army = memento.Army;
        this.Level = memento.Level;
        this.Economic = memento.Economic;
    }
}

④上端调用

KingsGlory kingsGlory = new KingsGlory()
{
    Hero = "甄姬-游梦惊园",
    Level = 1,
    Army = "法师*3 小兵*2",
    Economic = "200"
};
kingsGlory.Save();
kingsGlory.Show();

Console.WriteLine("*****第一波野怪*******");
kingsGlory.Level = 3;
kingsGlory.Army = "法师*3 小兵*2";
kingsGlory.Economic = "1K";
kingsGlory.Save();
kingsGlory.Show();

Console.WriteLine("********月光宝盒**********");
kingsGlory.Load();
kingsGlory.Show();

分析:由于把进度保持在第三方的容器Caretaker中,因此实现了进度回滚。但是我们可以看出此时保持了2次,但是结果只能回滚到最近的一次。如果要实现指定进度回滚该如何实现呢?

3:无限重生

①第三方容器添加进度条

public class Caretaker
{
    private static Dictionary _KingsGloryMementoDictionary = new Dictionary();
    public static void SaveKingsGloryMemento(string name, KingsGloryMemento kingsGloryMemento)
    {
        _KingsGloryMementoDictionary.Add(name, kingsGloryMemento);
    }

    public static KingsGloryMemento GetKingsGloryMemento(string name)
    {
        if (_KingsGloryMementoDictionary.ContainsKey(name))
            return _KingsGloryMementoDictionary[name];
        else
            throw new Exception("wrong name");
    }
}

②英雄职责调整,添加按照进度名称回滚

public class KingsGlory
{
    public string Hero { get; set; }
    public int Level { get; set; }
    public string Army { get; set; }
    public string Economic { get; set; }

    public void Show()
    {
        Console.WriteLine("********************************");
        Console.WriteLine("     Hero:{0}", this.Hero);
        Console.WriteLine("     Level:{0}级", this.Level);
        Console.WriteLine("     Army:{0}", this.Army);
        Console.WriteLine("     Economic:{0}", this.Economic);
        Console.WriteLine("********************************");
    }

    public void Save(string name)
    {
        KingsGloryMemento memento = new KingsGloryMemento(this.Level, this.Army, this.Economic);
        Caretaker.SaveKingsGloryMemento(name, memento);
    }

    public void Load(string name)
    {
        KingsGloryMemento memento = Caretaker.GetKingsGloryMemento(name);


        this.Army = memento.Army;
        this.Level = memento.Level;
        this.Economic = memento.Economic;
    }
}

③上端调用无限后悔

KingsGlory kingsGlory = new KingsGlory()
{
    Hero = "甄姬-游梦惊园",
    Level = 1,
    Army = "法师*3 小兵*2",
    Economic = "200"
};

kingsGlory.Save("Start");
kingsGlory.Show();

Console.WriteLine("*****第一波野怪*******");

kingsGlory.Level = 3;
kingsGlory.Army = "法师*3 小兵*2";
kingsGlory.Economic = "1K";
kingsGlory.Save("第一波野怪");
kingsGlory.Show();

Console.WriteLine("*****第一条暴君*******");
kingsGlory.Level = 5;
kingsGlory.Army = "法师*3 炮车*2";
kingsGlory.Economic = "3K";
kingsGlory.Show();
kingsGlory.Save("第一条暴君");

Console.WriteLine("*****第一条暗影主宰*******");
kingsGlory.Level = 8;
kingsGlory.Army = "超级兵*5";
kingsGlory.Economic = "5K";
kingsGlory.Show();
kingsGlory.Save("第一条暗影主宰");

Console.WriteLine("*****第一条黑暗暴君*******");
kingsGlory.Level = 12;
kingsGlory.Army = "主宰先锋*1";
kingsGlory.Economic = "10K";
kingsGlory.Show();
kingsGlory.Save("第一条黑暗暴君");

Console.WriteLine("********月光宝盒**********");
kingsGlory.Load("Start");
kingsGlory.Show();
kingsGlory.Load("第一波野怪");
kingsGlory.Show();
kingsGlory.Load("第一条暴君");
kingsGlory.Show();
kingsGlory.Load("第一条暗影主宰");
kingsGlory.Show();
kingsGlory.Load("第一条黑暗暴君");
kingsGlory.Show();

④运行结果

【手写源码-设计模式19】-备忘录模式-如果王者荣耀中有月光宝盒_第3张图片

4:备忘录模式的优缺点

1:优点

①状态恢复

备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史状态。

②多次撤销

备忘录实现了对信息的封装,保存了原发器的状态,配合列表,堆栈等集合可以实现多次撤销操作。

2:缺点

①资源消耗大

如果需要保存的原发器状态太多,将会占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源。

5:适用场景

①保存一个对象在某一个时刻的全部状态或部分状态,这样以后需要时就能恢复到先前的状态,实现撤销操作

②防止外界对象破坏一个对象历史状态的封装性,避免将历史状态的实现细节暴露给外部对象

6:应用实例

word文档的备份文件

虚拟机的镜像

下棋的悔棋动作

单机游戏的进度保持与加载

7:总结

人生没有彩排,每一天都是精彩的比赛,每一天都是现场直播。过去不会重来,未来无法预知,月光宝盒也不会等你1万年。接下来的日子,都请珍惜,把握好每次演出,便是对人生最好的珍惜。

你可能感兴趣的:(设计模式,c#,设计模式,架构师)