Head First设计模式之备忘录模式
一、定義
不破壞封裝性的前提下,捕獲一個(gè)對象的內(nèi)部狀態(tài),并在該對象之外保存這個(gè)狀態(tài)。這樣就可以將該對象恢復(fù)到原先保存的狀態(tài)
二、結(jié)構(gòu)
備忘錄模式中主要有三類角色:
- 發(fā)起人角色:記錄當(dāng)前時(shí)刻的內(nèi)部狀態(tài),負(fù)責(zé)創(chuàng)建和恢復(fù)備忘錄數(shù)據(jù)。
- 備忘錄角色:負(fù)責(zé)存儲發(fā)起人對象的內(nèi)部狀態(tài),在進(jìn)行恢復(fù)時(shí)提供給發(fā)起人需要的狀態(tài)。
- 管理者角色:負(fù)責(zé)保存?zhèn)渫泴ο?#xff0c;但是不能對備忘錄對象的內(nèi)容進(jìn)行操作或檢查。
三、適用場景
1、需要保存/恢復(fù)數(shù)據(jù)的相關(guān)狀態(tài)場景。
2、提供一個(gè)可回滾的操作。
四、優(yōu)缺點(diǎn)
優(yōu)點(diǎn):?
1、給用戶提供了一種可以恢復(fù)狀態(tài)的機(jī)制,可以使用戶能夠比較方便地回到某個(gè)歷史的狀態(tài)。
2、實(shí)現(xiàn)了信息的封裝,使得用戶不需要關(guān)心狀態(tài)的保存細(xì)節(jié)。
缺點(diǎn):
消耗資源。
1、如果類的成員變量過多,勢必會占用比較大的資源,而且每一次保存都會消耗一定的內(nèi)存。
2、由于備份的信息是由發(fā)起人自己提供的,所以管理者無法預(yù)知備份的信息的大小,存在一定的未知風(fēng)險(xiǎn)。
?
五、實(shí)現(xiàn)
下面以備份手機(jī)通訊錄為例子來實(shí)現(xiàn)了備忘錄模式,具體的實(shí)現(xiàn)代碼如下所示:
單次備份
// 聯(lián)系人public class ContactPerson{public string Name { get; set; }public string MobileNum { get; set; }}// 發(fā)起人public class MobileOwner{// 發(fā)起人需要保存的內(nèi)部狀態(tài)public List<ContactPerson> ContactPersons { get; set; }public MobileOwner(List<ContactPerson> persons){ContactPersons = persons;}// 創(chuàng)建備忘錄,將當(dāng)期要保存的聯(lián)系人列表導(dǎo)入到備忘錄中 public ContactMemento CreateMemento(){// 這里也應(yīng)該傳遞深拷貝,new List方式傳遞的是淺拷貝,// 因?yàn)镃ontactPerson類中都是string類型,所以這里new list方式對ContactPerson對象執(zhí)行了深拷貝// 如果ContactPerson包括非string的引用類型就會有問題,所以這里也應(yīng)該用序列化傳遞深拷貝return new ContactMemento(new List<ContactPerson>(this.ContactPersons));}// 將備忘錄中的數(shù)據(jù)備份導(dǎo)入到聯(lián)系人列表中public void RestoreMemento(ContactMemento memento){// 下面這種方式是錯誤的,因?yàn)檫@樣傳遞的是引用,// 則刪除一次可以恢復(fù),但恢復(fù)之后再刪除的話就恢復(fù)不了.// 所以應(yīng)該傳遞contactPersonBack的深拷貝,深拷貝可以使用序列化來完成this.ContactPersons = memento.contactPersonBack;}public void Show(){Console.WriteLine("聯(lián)系人列表中有{0}個(gè)人,他們是:", ContactPersons.Count);foreach (ContactPerson p in ContactPersons){Console.WriteLine("姓名: {0} 號碼為: {1}", p.Name, p.MobileNum);}}}// 備忘錄public class ContactMemento{// 保存發(fā)起人的內(nèi)部狀態(tài)public List<ContactPerson> contactPersonBack;public ContactMemento(List<ContactPerson> persons){contactPersonBack = persons;}}// 管理角色public class Caretaker{public ContactMemento ContactM { get; set; }}class Program{static void Main(string[] args){List<ContactPerson> persons = new List<ContactPerson>(){new ContactPerson() { Name= "Learning Hard", MobileNum = "123445"},new ContactPerson() { Name = "Tony", MobileNum = "234565"},new ContactPerson() { Name = "Jock", MobileNum = "231455"}};MobileOwner mobileOwner = new MobileOwner(persons);mobileOwner.Show();// 創(chuàng)建備忘錄并保存?zhèn)渫泴ο?/span>Caretaker caretaker = new Caretaker();caretaker.ContactM = mobileOwner.CreateMemento();// 更改發(fā)起人聯(lián)系人列表Console.WriteLine("----移除最后一個(gè)聯(lián)系人--------");mobileOwner.ContactPersons.RemoveAt(2);mobileOwner.Show();// 恢復(fù)到原始狀態(tài)Console.WriteLine("-------恢復(fù)聯(lián)系人列表------");mobileOwner.RestoreMemento(caretaker.ContactM);mobileOwner.Show();Console.Read();}}多次備份
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks;namespace DesignPatterns.Mememto {// 聯(lián)系人public class ContactPerson{public string Name { get; set; }public string MobileNum { get; set; }}// 發(fā)起人public class MobileOwner{public List<ContactPerson> ContactPersons { get; set; }public MobileOwner(List<ContactPerson> persons){ContactPersons = persons;}// 創(chuàng)建備忘錄,將當(dāng)期要保存的聯(lián)系人列表導(dǎo)入到備忘錄中 public ContactMemento CreateMemento(){// 這里也應(yīng)該傳遞深拷貝,new List方式傳遞的是淺拷貝,// 因?yàn)镃ontactPerson類中都是string類型,所以這里new list方式對ContactPerson對象執(zhí)行了深拷貝// 如果ContactPerson包括非string的引用類型就會有問題,所以這里也應(yīng)該用序列化傳遞深拷貝return new ContactMemento(new List<ContactPerson>(this.ContactPersons));}// 將備忘錄中的數(shù)據(jù)備份導(dǎo)入到聯(lián)系人列表中public void RestoreMemento(ContactMemento memento){if (memento != null){// 下面這種方式是錯誤的,因?yàn)檫@樣傳遞的是引用,// 則刪除一次可以恢復(fù),但恢復(fù)之后再刪除的話就恢復(fù)不了.// 所以應(yīng)該傳遞contactPersonBack的深拷貝,深拷貝可以使用序列化來完成this.ContactPersons = memento.ContactPersonBack;}}public void Show(){Console.WriteLine("聯(lián)系人列表中有{0}個(gè)人,他們是:", ContactPersons.Count);foreach (ContactPerson p in ContactPersons){Console.WriteLine("姓名: {0} 號碼為: {1}", p.Name, p.MobileNum);}}}// 備忘錄public class ContactMemento{public List<ContactPerson> ContactPersonBack { get; set; }public ContactMemento(List<ContactPerson> persons){ContactPersonBack = persons;}}// 管理角色public class Caretaker{// 使用多個(gè)備忘錄來存儲多個(gè)備份點(diǎn)public Dictionary<string, ContactMemento> ContactMementoDic { get; set; }public Caretaker(){ContactMementoDic = new Dictionary<string, ContactMemento>();}}class Program{static void Main(string[] args){List<ContactPerson> persons = new List<ContactPerson>(){new ContactPerson() { Name= "Learning Hard", MobileNum = "123445"},new ContactPerson() { Name = "Tony", MobileNum = "234565"},new ContactPerson() { Name = "Jock", MobileNum = "231455"}};MobileOwner mobileOwner = new MobileOwner(persons);mobileOwner.Show();// 創(chuàng)建備忘錄并保存?zhèn)渫泴ο?/span>Caretaker caretaker = new Caretaker();caretaker.ContactMementoDic.Add(DateTime.Now.ToString(), mobileOwner.CreateMemento());// 更改發(fā)起人聯(lián)系人列表Console.WriteLine("----移除最后一個(gè)聯(lián)系人--------");mobileOwner.ContactPersons.RemoveAt(2);mobileOwner.Show();// 創(chuàng)建第二個(gè)備份Thread.Sleep(1000);caretaker.ContactMementoDic.Add(DateTime.Now.ToString(), mobileOwner.CreateMemento());// 恢復(fù)到原始狀態(tài)Console.WriteLine("-------恢復(fù)聯(lián)系人列表,請從以下列表選擇恢復(fù)的日期------");var keyCollection = caretaker.ContactMementoDic.Keys;foreach (string k in keyCollection){Console.WriteLine("Key = {0}", k);}while (true){Console.Write("請輸入數(shù)字,按窗口的關(guān)閉鍵退出:");int index = -1;try{index = Int32.Parse(Console.ReadLine());}catch{Console.WriteLine("輸入的格式錯誤");continue;}ContactMemento contactMentor = null;if (index < keyCollection.Count && caretaker.ContactMementoDic.TryGetValue(keyCollection.ElementAt(index), out contactMentor)){mobileOwner.RestoreMemento(contactMentor);mobileOwner.Show();}else{Console.WriteLine("輸入的索引大于集合長度!");}}}} }?
?
參考
http://www.cnblogs.com/JsonShare/p/7283972.html
http://www.runoob.com/design-pattern/memento-pattern.html
http://www.cnblogs.com/zhili/p/MementoPattern.html
?
歡迎閱讀本系列文章:Head First設(shè)計(jì)模式之目錄?
?
轉(zhuǎn)載于:https://www.cnblogs.com/xcsn/p/7498695.html
總結(jié)
以上是生活随笔為你收集整理的Head First设计模式之备忘录模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JAVA中常用的逻辑运算符_Java中的
- 下一篇: 【自动化__持续集成】___java__