备忘录模式(17)
今天,我们来讲备忘录模式
一、案例:
小伙伴们都玩过单机游戏或者说RPG类的游戏吧,我们在打BOSS之前,需要先存一下档,以免BOSS打不过从头再来,好,下面,我们用简单的控制台应用程序来描述一下这个场景。
1 /// <summary> 2 /// 游戏角色类 3 /// </summary> 4 class GameRole 5 { 6 //生命值 7 private int vit; 8 9 public int Vit 10 { 11 get 12 { 13 return vit; 14 } 15 16 set 17 { 18 vit = value; 19 } 20 } 21 //攻击力 22 private int atk; 23 public int Def 24 { 25 get 26 { 27 return def; 28 } 29 30 set 31 { 32 def = value; 33 } 34 } 35 private int def; 36 //防御力 37 public int Atk 38 { 39 get 40 { 41 return atk; 42 } 43 44 set 45 { 46 atk = value; 47 } 48 } 49 //状态显示 50 public void StateDisplay() 51 { 52 Console.WriteLine("角色当前状态:"); 53 Console.WriteLine($"体力:{this.vit}"); 54 Console.WriteLine($"攻击力:{this.atk}"); 55 Console.WriteLine($"防御力:{this.def}"); 56 Console.WriteLine(""); 57 } 58 /// <summary> 59 /// 获取初始状态 60 /// 数据通常来自本机磁盘或远程数据库 61 /// </summary> 62 public void GetInitState() 63 { 64 this.vit = 100; 65 this.atk = 100; 66 this.def = 100; 67 } 68 /// <summary> 69 /// 战斗 70 /// 在与Boss大战后游戏数据损耗为0 71 /// </summary> 72 public void Fight() 73 { 74 this.vit = 0; 75 this.atk = 0; 76 this.def = 0; 77 } 78 }
客户端调用:
1 public static void Main() 2 { 3 //大战Boss前 4 GameRole lixiaoyao = new GameRole(); 5 //大战Boss前,获得初始角色状态 6 lixiaoyao.GetInitState(); 7 lixiaoyao.StateDisplay(); 8 9 //保存进度,通过‘游戏角色’的新实例来保存进度 10 GameRole backup = new GameRole(); 11 backup.Vit = lixiaoyao.Vit; 12 backup.Atk = lixiaoyao.Atk; 13 backup.Def = lixiaoyao.Def; 14 15 //大战Boss 损耗很严重 16 lixiaoyao.Fight(); 17 lixiaoyao.StateDisplay(); 18 19 //恢复之前状态 20 lixiaoyao.Vit = backup.Vit; 21 lixiaoyao.Atk = backup.Atk; 22 lixiaoyao.Def = backup.Def; 23 lixiaoyao.StateDisplay(); 24 Console.ReadKey(); 25 }
好了,我们很好的描述了我们案例中的场景,那下面,我们看一下我们这段代码有什么不足吗?请看
//保存进度,通过‘游戏角色’的新实例来保存进度 GameRole backup = new GameRole(); backup.Vit = lixiaoyao.Vit; backup.Atk = lixiaoyao.Atk; backup.Def = lixiaoyao.Def;
//恢复之前状态 lixiaoyao.Vit = backup.Vit; lixiaoyao.Atk = backup.Atk; lixiaoyao.Def = backup.Def; lixiaoyao.StateDisplay();
这两段代码在客户端暴露了细节,客户端的责任太多了,要知道角色的状态,还要备份,如果今后需要对角色增加 魔力值 这个属性,那都是非常麻烦的事情了。
显然,我们希望将角色的存取状态细节封存起来,最好是封装在外部的类当中,以体现职责分离。
面对上述的要求,这里,我们就需要学习一种新的设计模式了,备忘录模式。
备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样就可以将对象恢复到原先保存的那个状态。
好,下面我们来看一下设计模式的基本结构代码,需要三个类
1 /// <summary> 2 /// 发起人类 3 /// </summary> 4 class Originator 5 { 6 /// <summary> 7 /// 需要保存的属性,可以是多个 8 /// </summary> 9 private string state; 10 11 public string State 12 { 13 get 14 { 15 return state; 16 } 17 18 set 19 { 20 state = value; 21 } 22 } 23 /// <summary> 24 /// 创建备忘录,将当前需要保存的信息导入并实例化出一个Memento对象 25 /// </summary> 26 /// <returns></returns> 27 public Memento CraeteMemento() 28 { 29 return new Memento(state); 30 } 31 32 public void SetMemento(Memento memento) 33 { 34 state = memento.State; 35 } 36 /// <summary> 37 /// 显示数据 38 /// </summary> 39 public void Show() 40 { 41 Console.WriteLine($"State={state}"); 42 } 43 } 44 /// <summary> 45 /// 备忘录类 46 /// </summary> 47 class Memento 48 { 49 private string state; 50 /// <summary> 51 /// 构造方法,将相关数据导入 52 /// </summary> 53 /// <param name="state"></param> 54 public Memento(string state) 55 { 56 this.state = state; 57 } 58 /// <summary> 59 /// 需要保存的数据属性,可以是多个 60 /// </summary> 61 public string State 62 { 63 get { return state; } 64 } 65 } 66 /// <summary> 67 /// 管理者 68 /// </summary> 69 class Caretaker 70 { 71 /// <summary> 72 /// 属性,得到或设置备忘录 73 /// </summary> 74 private Memento memento; 75 76 internal Memento Memento 77 { 78 get 79 { 80 return memento; 81 } 82 83 set 84 { 85 memento = value; 86 } 87 } 88 }
客户端调用:
1 public static void Main() 2 { 3 //Originator 初始状态,状态属性为”On“ 4 Originator o = new Originator(); 5 o.State = "On"; 6 o.Show(); 7 8 //保存状态时,由于有了很好的封装,可以隐藏Originator的实现细节 9 Caretaker c = new Caretaker(); 10 c.Memento = o.CraeteMemento(); 11 12 //改变Originator状态为”Off“ 13 o.State = "Off"; 14 o.Show(); 15 16 //恢复原始状态 17 o.SetMemento(c.Memento); 18 o.Show(); 19 Console.ReadKey(); 20 }
好,我们就用备忘录模式来写一下我们案例中的代码
1 /// <summary> 2 /// 游戏角色类(发起者) 3 /// </summary> 4 class GameRole 5 { 6 //生命值 7 private int vit; 8 9 public int Vit 10 { 11 get 12 { 13 return vit; 14 } 15 16 set 17 { 18 vit = value; 19 } 20 } 21 //攻击力 22 private int atk; 23 public int Def 24 { 25 get 26 { 27 return def; 28 } 29 30 set 31 { 32 def = value; 33 } 34 } 35 private int def; 36 //防御力 37 public int Atk 38 { 39 get 40 { 41 return atk; 42 } 43 44 set 45 { 46 atk = value; 47 } 48 } 49 //状态显示 50 public void StateDisplay() 51 { 52 Console.WriteLine("角色当前状态:"); 53 Console.WriteLine($"体力:{this.vit}"); 54 Console.WriteLine($"攻击力:{this.atk}"); 55 Console.WriteLine($"防御力:{this.def}"); 56 Console.WriteLine(""); 57 } 58 /// <summary> 59 /// 获取初始状态 60 /// 数据通常来自本机磁盘或远程数据库 61 /// </summary> 62 public void GetInitState() 63 { 64 this.vit = 100; 65 this.atk = 100; 66 this.def = 100; 67 } 68 /// <summary> 69 /// 战斗 70 /// 在与Boss大战后游戏数据损耗为0 71 /// </summary> 72 public void Fight() 73 { 74 this.vit = 0; 75 this.atk = 0; 76 this.def = 0; 77 } 78 /// <summary> 79 /// 保存角色状态 80 /// </summary> 81 /// <returns></returns> 82 public RoleStateMemtento SaveState() 83 { 84 return new RoleStateMemtento(vit, atk, def); 85 } 86 /// <summary> 87 /// 恢复角色状态 88 /// </summary> 89 /// <param name="memento"></param> 90 public void RecoverState(RoleStateMemtento memento) 91 { 92 this.vit = memento.Vit; 93 this.atk = memento.Atk; 94 this.def = memento.Def; 95 } 96 } 97 /// <summary> 98 /// 角色状态储存箱(备忘录) 99 /// </summary> 100 class RoleStateMemtento 101 { 102 private int vit; 103 private int atk; 104 private int def; 105 106 public int Vit 107 { 108 get 109 { 110 return vit; 111 } 112 113 set 114 { 115 vit = value; 116 } 117 } 118 119 public int Atk 120 { 121 get 122 { 123 return atk; 124 } 125 126 set 127 { 128 atk = value; 129 } 130 } 131 132 public int Def 133 { 134 get 135 { 136 return def; 137 } 138 139 set 140 { 141 def = value; 142 } 143 } 144 /// <summary> 145 /// 将生命力,攻击力,防御力 存入状态存储箱对象中 146 /// </summary> 147 /// <param name="vit"></param> 148 /// <param name="atk"></param> 149 /// <param name="def"></param> 150 public RoleStateMemtento(int vit, int atk, int def) 151 { 152 this.vit = vit; 153 this.atk = atk; 154 this.def = def; 155 } 156 } 157 /// <summary> 158 /// 管理者 159 /// </summary> 160 class RoleStateCaretaker 161 { 162 private RoleStateMemtento memento; 163 164 internal RoleStateMemtento Memento 165 { 166 get 167 { 168 return memento; 169 } 170 171 set 172 { 173 memento = value; 174 } 175 } 176 }
客户端调用:
1 public static void Main() 2 { 3 //大战Boss前 4 //游戏角色初始状态,三项指标都为100 5 GameRole lixiaoyao = new GameRole(); 6 lixiaoyao.GetInitState(); 7 lixiaoyao.StateDisplay(); 8 9 //保存进度 10 //保存进度时,由于封装在Memento中,因此,我们并不知道保存了哪些具体的角色数据 11 RoleStateCaretaker stateAdmin = new RoleStateCaretaker(); 12 stateAdmin.Memento = lixiaoyao.SaveState(); 13 14 //大战Boss,损耗严重 15 //三项指标都为0,GameOver了。 16 lixiaoyao.Fight(); 17 lixiaoyao.StateDisplay(); 18 19 //恢复之前状态 20 lixiaoyao.RecoverState(stateAdmin.Memento); 21 lixiaoyao.StateDisplay(); 22 Console.ReadKey(); 23 }
好了,今天备忘录模式就讲到这里,下一篇博文,我们讲 组合模式
本系列将持续更新,喜欢的小伙伴可以点一下关注和推荐,谢谢大家的支持
努力,不是为了要感动谁,也不是要做给哪个人看,而是要让自己随时有能力跳出自己厌恶的圈子,并拥有选择的权利。记住,用自己喜欢的方式过一生。