深入理解Java設(shè)計模式之備忘錄模式
一、什么是備忘錄模式
定義:在不破壞封閉的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)。這樣以后就可將該對象恢復(fù)到原先保存的狀態(tài)。
該模式用于保存對象當(dāng)前狀態(tài),并且在之后可以再次恢復(fù)到此狀態(tài)。備忘錄模式實現(xiàn)的方式需要保證被保存的對象狀態(tài)不能被對象從外部訪問,
目的是為了保護(hù)被保存的這些對象狀態(tài)的完整性以及內(nèi)部實現(xiàn)不向外暴露
二、備忘錄模式的結(jié)構(gòu)

涉及角色:
1.Originator(發(fā)起人):負(fù)責(zé)創(chuàng)建一個備忘錄Memento,用以記錄當(dāng)前時刻自身的內(nèi)部狀態(tài),并可使用備忘錄恢復(fù)內(nèi)部狀態(tài)。Originator可以根據(jù)需要決定Memento存儲自己的哪些內(nèi)部狀態(tài)。
2.Memento(備忘錄):負(fù)責(zé)存儲Originator對象的內(nèi)部狀態(tài),并可以防止Originator以外的其他對象訪問備忘錄。備忘錄有兩個接口:Caretaker只能看到備忘錄的窄接口,他只能將備忘錄傳遞給其他對象。Originator卻可看到備忘錄的寬接口,允許它訪問返回到先前狀態(tài)所需要的所有數(shù)據(jù)。
3.Caretaker(管理者):負(fù)責(zé)備忘錄Memento,不能對Memento的內(nèi)容進(jìn)行訪問或者操作。
三、備忘錄模式的使用場景
1.需要保存和恢復(fù)數(shù)據(jù)的相關(guān)狀態(tài)場景。
2.提供一個可回滾(rollback)的操作。
3.數(shù)據(jù)庫連接的事務(wù)管理就是用的備忘錄模式。
四、備忘錄模式的優(yōu)缺點
優(yōu)點:
1、有時一些發(fā)起人對象的內(nèi)部信息必須保存在發(fā)起人對象以外的地方,但是必須要由發(fā)起人對象自己讀取,這時,使用備忘錄模式可以把復(fù)雜的發(fā)起人內(nèi)部信息對其他的對象屏蔽起來,從而可以恰當(dāng)?shù)乇3址庋b的邊界。
2、本模式簡化了發(fā)起人類。發(fā)起人不再需要管理和保存其內(nèi)部狀態(tài)的一個個版本,客戶端可以自行管理他們所需要的這些狀態(tài)的版本。
3、當(dāng)發(fā)起人角色的狀態(tài)改變的時候,有可能這個狀態(tài)無效,這時候就可以使用暫時存儲起來的備忘錄將狀態(tài)復(fù)原。
缺點:
1、如果發(fā)起人角色的狀態(tài)需要完整地存儲到備忘錄對象中,那么在資源消耗上面?zhèn)渫泴ο髸馨嘿F。
2、當(dāng)負(fù)責(zé)人角色將一個備忘錄 存儲起來的時候,負(fù)責(zé)人可能并不知道這個狀態(tài)會占用多大的存儲空間,從而無法提醒用戶一個操作是否很昂貴。
3、當(dāng)發(fā)起人角色的狀態(tài)改變的時候,有可能這個協(xié)議無效。如果狀態(tài)改變的成功率不高的話,不如采取“假如”協(xié)議模式。
五、備忘錄模式的實現(xiàn)
實例:備份電話本
聯(lián)系人--需要備份的數(shù)據(jù),是狀態(tài)數(shù)據(jù),沒有操作
public sealed class ContactPerson
{
//姓名
public string Name { get; set; }
//電話號碼
public string MobileNumber { get; set; }
}
發(fā)起人--相當(dāng)于【發(fā)起人角色】Originator
public sealed class MobileBackOriginator
{
// 發(fā)起人需要保存的內(nèi)部狀態(tài)
private List<ContactPerson> _personList;
public List<ContactPerson> ContactPersonList
{
get
{
return this._personList;
}
set
{
this._personList = value;
}
}
//初始化需要備份的電話名單
public MobileBackOriginator(List<ContactPerson> personList)
{
if (personList != null)
{
this._personList = personList;
}
else
{
throw new ArgumentNullException("參數(shù)不能為空!");
}
}
// 創(chuàng)建備忘錄對象實例,將當(dāng)期要保存的聯(lián)系人列表保存到備忘錄對象中
public ContactPersonMemento CreateMemento()
{
return new ContactPersonMemento(new List<ContactPerson>(this._personList));
}
// 將備忘錄中的數(shù)據(jù)備份還原到聯(lián)系人列表中
public void RestoreMemento(ContactPersonMemento memento)
{
this.ContactPersonList = memento.ContactPersonListBack;
}
public void Show()
{
Console.WriteLine("聯(lián)系人列表中共有{0}個人,他們是:", ContactPersonList.Count);
foreach (ContactPerson p in ContactPersonList)
{
Console.WriteLine("姓名: {0} 號碼: {1}", p.Name, p.MobileNumber);
}
}
}
備忘錄對象,用于保存狀態(tài)數(shù)據(jù),保存的是當(dāng)時對象具體狀態(tài)數(shù)據(jù)--相當(dāng)于【備忘錄角色】Memeto
public sealed class ContactPersonMemento
{
// 保存發(fā)起人創(chuàng)建的電話名單數(shù)據(jù),就是所謂的狀態(tài)
public List<ContactPerson> ContactPersonListBack { get; private set; }
public ContactPersonMemento(List<ContactPerson> personList)
{
ContactPersonListBack = personList;
}
}
管理角色,它可以管理【備忘錄】對象,如果是保存多個【備忘錄】對象,當(dāng)然可以對保存的對象進(jìn)行增、刪等管理處理---相當(dāng)于【管理者角色】Caretaker
public sealed class MementoManager
{
//如果想保存多個【備忘錄】對象,可以通過字典或者堆棧來保存,堆棧對象可以反映保存對象的先后順序
//比如:public Dictionary<string, ContactPersonMemento> ContactPersonMementoDictionary { get; set; }
public ContactPersonMemento ContactPersonMemento { get; set; }
}
客戶端代碼
class Program
{
static void Main(string[] args)
{
List<ContactPerson> persons = new List<ContactPerson>()
{
new ContactPerson() { Name="黃飛鴻", MobileNumber = "13533332222"},
new ContactPerson() { Name="方世玉", MobileNumber = "13966554433"},
new ContactPerson() { Name="洪熙官", MobileNumber = "13198765544"}
};
//手機(jī)名單發(fā)起人
MobileBackOriginator mobileOriginator = new MobileBackOriginator(persons);
mobileOriginator.Show();
// 創(chuàng)建備忘錄并保存?zhèn)渫泴ο?
MementoManager manager = new MementoManager();
manager.ContactPersonMemento = mobileOriginator.CreateMemento();
// 更改發(fā)起人聯(lián)系人列表
Console.WriteLine("----移除最后一個聯(lián)系人--------");
mobileOriginator.ContactPersonList.RemoveAt(2);
mobileOriginator.Show();
// 恢復(fù)到原始狀態(tài)
Console.WriteLine("-------恢復(fù)聯(lián)系人列表------");
mobileOriginator.RestoreMemento(manager.ContactPersonMemento);
mobileOriginator.Show();
Console.Read();
}
}
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之際的更多內(nèi)容!
相關(guān)文章
說說@ModelAttribute在父類和子類中的執(zhí)行順序
這篇文章主要介紹了@ModelAttribute在父類和子類中的執(zhí)行順序,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06
java9的JShell小工具和編譯器兩種自動優(yōu)化方法
這篇文章主要介紹了java9的JShell小工具和編譯器兩種自動優(yōu)化方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-07-07
Spring profile通過多種方法實現(xiàn)多環(huán)境支持
這篇文章主要介紹了Spring profile通過多種方法實現(xiàn)多環(huán)境支持,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10
MyBatis中的SQL映射文件如何配置參數(shù)映射和使用方法
MyBatis 是一種開源的 Java 持久化框架,它可以自動將數(shù)據(jù)庫中的數(shù)據(jù)映射到 Java 對象中,并且使得 Java 對象可以非常方便地存儲到數(shù)據(jù)庫中,本文將介紹 MyBatis 中 SQL 映射文件的參數(shù)映射配置和使用方法,需要的朋友可以參考下2023-07-07

