zoukankan      html  css  js  c++  java
  • 面向对象编程思想-备忘录模式

    一、引言

    上篇博文中我们分享了访问者模式,访问者模式是把作用于数据结构上的操作封装到访问者类中,使得数据结构与操作分离。今天我们要学习的备忘录模式与命令模式有点相似,不同的是,命令模式保存的是发起人的具体命令(命令对应行为),而备忘录模式保存的是发起人的状态(状态对应数据内部结构,如属性)。下面请看今天要学习的访问者模式

    二、备忘录模式

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

    下面是备忘录模式的结构图:

    下面是备忘录模式代码demo:

        //发起人
        class Originator
        {
            private string state;
            public string State
            {
                get { return state; }
                set { state = value; }
            }
            //通过实例化备忘录 保存状态
            public Memento CreateMemento()
            {
                return new Memento(state);
            }
            //将备忘录中状态恢复给发起人
            public void SetMemento(Memento memento)
            {
                this.state = memento.State;
            }
            public void Show()
            {
                Console.WriteLine($"当前state为{State}");
            }
        }
        //备忘录类
        class Memento
        {
            private string state;
            public Memento(string state)
            {
                this.state = state;
            }
            public string State
            {
                get { return state; }
            }
        }
        //管理者类,负责保存备忘录
        class Caretaker
        {
            private Memento memento;
            public Memento Memento
            {
                get { return memento; }
                set { memento = value; }
            }
        }
         class Program
        {
            static void Main(string[] args)
            {
                //创建发起人  (修改状态前)
                Originator originator = new Originator();
                originator.State = "我现在感觉很充实";
                originator.Show();
                //保存状态  由于封装在Memento中,因此客户端并不知道保存了哪些具体的发起人数据
                Caretaker caretaker = new Caretaker();
                caretaker.Memento = originator.CreateMemento();
                //修改状态
                originator.State = "稍微有一点点的饿";
                originator.Show();
                //恢复状态
                originator.SetMemento(caretaker.Memento);
                originator.Show();
                Console.Read();
            }
        }
    View Code

    分析:把保存状态的细节封装到Memento中,这样哪天更改保存的细节也不会影响客户端。使用备忘录模式可以将复杂对象的内部信息对其他对象屏蔽起来。当角色状态改变时,有可能这个状态无效,可以使用暂时存储的备忘录将状态复原。

    下面是多状态多备份备忘录实例:

        //游戏进度类
        class GameState
        {
            //生命力
            public string Vitality { get; set; }
            //攻击力
            public string Attackpower { get; set; }
            //防御力
            public string Defense { get; set; }
        }
        //游戏发起人
        class GamePlayer
        {
            public List<GameState> LstGameState { get; set; }
            public GamePlayer(List<GameState> lstGameState)
            {
                this.LstGameState = lstGameState;
            }
            //创建备忘录,将要保存的游戏进度列表导入备忘录
            public GameMemento CreateGameMemento()
            {
                return new GameMemento(new List<GameState>(this.LstGameState)); 
            }
            //将备忘录中数据备份导入游戏进度列表
            public void SetGameMemento(GameMemento gameMemento)
            {
                if (gameMemento != null)
                {
                    this.LstGameState = gameMemento.LstGameStateBak;
                }
            }
            public void Show()
            {
                Console.WriteLine($"游戏保存了{LstGameState.Count}个进度,分别是");
                foreach (GameState gameState in LstGameState)
                {
                    Console.WriteLine($"生命力{gameState.Vitality},攻击力{gameState.Attackpower},防御力{gameState.Defense}");
                }
            }
        }
         //备忘录
        class GameMemento
        {
            public List<GameState> LstGameStateBak { get; set; }
            public GameMemento(List<GameState> lstGameState)
            {
                this.LstGameStateBak = lstGameState;
            }
        }
         class GameCaretaker
        {
            //使用多个备忘录来储存备份点
            public Dictionary<string,GameMemento> DicGameMemento { get; set; }
            public GameCaretaker()
            {
                DicGameMemento = new Dictionary<string, GameMemento>();
            }
        }
         class Program
        {
            static void Main(string[] args)
            {
                List<GameState> lstGameState = new List<GameState>()
                {
                   new GameState(){Vitality="100",Attackpower="100",Defense="100"},
                   new GameState(){Vitality="80",Attackpower="80",Defense="80"},
                   new GameState(){Vitality="50",Attackpower="50",Defense="50"}
                };
                GamePlayer gamePlayer = new GamePlayer(lstGameState);
                gamePlayer.Show();
                //创建备忘录并保存进度
                GameCaretaker gameCaretaker = new GameCaretaker();
                gameCaretaker.DicGameMemento.Add(DateTime.Now.ToString(),gamePlayer.CreateGameMemento());
                //移除最后一个游戏进度
                gamePlayer.LstGameState.RemoveAt(2);
                gamePlayer.Show();
                Thread.Sleep(1000);
                //第二次备份
                gameCaretaker.DicGameMemento.Add(DateTime.Now.ToString(), gamePlayer.CreateGameMemento());
                //恢复到指定进度
                var keyCollection = gameCaretaker.DicGameMemento.Keys;
                foreach (string k in keyCollection)
                {
                    Console.WriteLine($"key={k}");
                }
                while (true)
                {
                    Console.WriteLine("请输入数字,按关闭键退出");
                    int index = -1;
                    try
                    {
                        index = Int32.Parse(Console.ReadLine());
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("输入的字符格式不正确");
                        continue;
                    }
                    GameMemento gameMemento = null;
                    if(index>-1&& index< gamePlayer.LstGameState.Count && gameCaretaker.DicGameMemento.TryGetValue(keyCollection.ElementAt(index),out gameMemento))
                    {
                        gamePlayer.SetGameMemento(gameMemento);
                        gamePlayer.Show();
                    }
                    else
                    {
                        Console.WriteLine("索引超出界限");
                    }
                }
            }
        }
    View Code

    分析:实际应用中,大多情况下用到的是多状态多备份,如果状态很大很多,备忘录对象会很耗内存

    优点

    1.如果某个操作错误破坏了数据的完整性,可以使用备忘录模式恢复原来保存的数据

    2.备份的状态保存在发起人之外,这样发起人就不需要对各个保存的状态进行管理。

    缺点

    1.在实际系统中,可能需要多状态多备份,对系统资源消耗是比较大的

    适用场景

    1.如果系统需要提供回滚操作时,使用备忘录模式是比较方便的。例如数据库中事务操作,文本编辑器中的Ctrl+Z撤销操作

    参考:

    大话设计模式

    http://www.cnblogs.com/zhili/p/MementoPattern.html;

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

  • 相关阅读:
    js_未结束的字符串常量
    [转]关于项目管理的思考
    Nhibernate理解
    Visual Studio 2005常用插件搜罗
    基本概念
    resharper 2.0
    Nhibernate资源
    [转]关于项目管理的知识点
    style
    带分数 蓝桥杯
  • 原文地址:https://www.cnblogs.com/jdzhang/p/7435918.html
Copyright © 2011-2022 走看看