设计模式-行为型-备忘录模式
备忘录模式(Memento):
后悔药来啦!!!备忘录模式在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便在需要时能将该对象恢复到原先保存的状态。
备忘录模式的角色:
1)发起人(Originator):记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
2)备忘录(Memento):负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
3)管理者(CareTaker):对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
根据上述UML图实现代码:
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 Originator o = new Originator(); 6 o.State = "On"; 7 8 Caretaker c = new Caretaker(); 9 c.Memento = o.CreateMemento(); 10 11 o.State = "Off"; 12 o.SetMemento(c.Memento); 13 } 14 } 15 16 /// <summary> 17 /// 备忘录 18 /// </summary> 19 public class Memento 20 { 21 private string _state; 22 23 public Memento(string state) 24 { 25 this._state = state; 26 } 27 28 public string State 29 { 30 get { return _state; } 31 } 32 } 33 34 /// <summary> 35 /// 发起人 36 /// </summary> 37 public class Originator 38 { 39 private string _state; 40 41 public string State 42 { 43 get 44 { 45 return _state; 46 } 47 set 48 { 49 _state = value; 50 Console.WriteLine("State = " + _state); 51 } 52 } 53 54 public Memento CreateMemento() 55 { 56 return (new Memento(_state)); 57 } 58 59 public void SetMemento(Memento memento) 60 { 61 Console.WriteLine("Restoring state..."); 62 State = memento.State; 63 } 64 } 65 66 /// <summary> 67 /// 管理者 68 /// </summary> 69 public class Caretaker 70 { 71 private Memento _memento; 72 73 public Memento Memento 74 { 75 get 76 { 77 return _memento; 78 } 79 set 80 { 81 _memento = value; 82 } 83 } 84 }
现实生活中,我们往往会进行文档的备份或者SVN,git的快照。
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 List<Document> docs = new List<Document>() 6 { 7 new Document{ Name="水浒传", Content="水浒传123131231" }, 8 new Document{ Name="三国演义", Content="三国演义111111" } 9 }; 10 11 Originator originator = new Originator(docs); 12 Caretaker caretaker = new Caretaker(); 13 DateTimeOffset time1 = new DateTimeOffset(DateTime.Now); 14 caretaker.MementoDic.Add(time1, originator.CreateMemento()); 15 originator.GetShow(); 16 Console.WriteLine("===================================="); 17 Console.WriteLine("修改内容"); 18 docs[0].Content = "新水浒,搞笑ing"; 19 DateTimeOffset time2 = new DateTimeOffset(DateTime.Now); 20 caretaker.MementoDic.Add(time2, originator.CreateMemento()); 21 originator.GetShow(); 22 Console.WriteLine("===================================="); 23 Console.WriteLine("回滚到第一阶段"); 24 originator.SetMemento(caretaker.MementoDic[time1]); 25 originator.GetShow(); 26 Console.WriteLine("回滚到第二阶段"); 27 originator.SetMemento(caretaker.MementoDic[time2]); 28 originator.GetShow(); 29 } 30 } 31 32 /// <summary> 33 /// 文件 34 /// </summary> 35 public class Document 36 { 37 public string Name { get; set; } 38 public string Content { get; set; } 39 } 40 41 /// <summary> 42 /// 备忘录 43 /// </summary> 44 public class Memento 45 { 46 public List<Document> fileBack; 47 48 public Memento(List<Document> docs) 49 { 50 this.fileBack = docs; 51 } 52 } 53 54 /// <summary> 55 /// 发起人 56 /// </summary> 57 public class Originator 58 { 59 //内部状态 60 public List<Document> docs; 61 62 public Originator(List<Document> docs) 63 { 64 this.docs = docs; 65 } 66 67 public Memento CreateMemento() 68 { 69 // 深拷贝传递对象 70 var str = JsonConvert.SerializeObject(this.docs); 71 return new Memento(JsonConvert.DeserializeObject<List<Document>>(str)); 72 } 73 74 public void SetMemento(Memento memento) 75 { 76 Console.WriteLine("Restoring state..."); 77 docs = memento.fileBack; 78 } 79 80 /// <summary> 81 /// 显示信息 82 /// </summary> 83 public void GetShow() 84 { 85 foreach (var doc in docs) 86 { 87 Console.WriteLine($"文件名:{doc.Name},内容:{doc.Content}"); 88 } 89 } 90 } 91 92 /// <summary> 93 /// 管理者 94 /// </summary> 95 public class Caretaker 96 { 97 // 使用多个备忘录来存储多个备份点 98 public Dictionary<DateTimeOffset, Memento> MementoDic { get; set; } 99 100 public Caretaker() 101 { 102 MementoDic = new Dictionary<DateTimeOffset, Memento>(); 103 } 104 }
备忘录模式的优缺点:
优点:
1)给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。
2)实现了信息的封装,使得用户不需要关心状态的保存细节。
缺点:消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。
备忘录模式的应用场景:
1)需要保存/恢复数据的相关状态场景。
2)提供一个可回滚的操作。
参考:https://blog.csdn.net/heyangyi_19940703/article/details/51376570