備忘錄模式概述
備忘錄模式提供了一種狀態(tài)恢復的實現(xiàn)機制,使得用戶可以方便地回到一個特定的歷史步驟,當新的狀態(tài)無效或者存在問題時,可以使用暫時存儲起來的備忘錄將狀態(tài)復原,當前很多軟件都提供了撤銷(Undo)操作,其中就使用了備忘錄模式。
備忘錄模式定義如下:
備忘錄模式(Memento Pattern):在不破壞封裝的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài),這樣可以在以后將對象恢復到原先保存的狀態(tài)。它是一種對象行為型模式,其別名為Token。
備忘錄模式的核心是備忘錄類以及用于管理備忘錄的負責人類的設(shè)計,其結(jié)構(gòu)如圖21-3所示:
[圖片上傳中。。。(6)]
在備忘錄模式結(jié)構(gòu)圖中包含如下幾個角色:
● Originator(原發(fā)器):它是一個普通類,可以創(chuàng)建一個備忘錄,并存儲它的當前內(nèi)部狀態(tài),也可以使用備忘錄來恢復其內(nèi)部狀態(tài),一般將需要保存內(nèi)部狀態(tài)的類設(shè)計為原發(fā)器。
** ●Memento(備忘錄):存儲原發(fā)器的內(nèi)部狀態(tài),根據(jù)原發(fā)器來決定保存哪些內(nèi)部狀態(tài)。備忘錄的設(shè)計一般可以參考原發(fā)器的設(shè)計,根據(jù)實際需要確定備忘錄類中的屬性。需要注意的是,除了原發(fā)器本身與負責人類之外,備忘錄對象不能直接供其他類使用,原發(fā)器的設(shè)計在不同的編程語言中實現(xiàn)機制會有所不同。
●Caretaker(負責人):負責人又稱為管理者,它負責保存?zhèn)渫?,但是不能對備忘錄的?nèi)容進行操作或檢查。在負責人類中可以存儲一個或多個備忘錄對象,它只負責存儲對象,而不能修改對象,也無須知道對象的實現(xiàn)細節(jié)。
理解備忘錄模式并不難,但關(guān)鍵在于如何設(shè)計備忘錄類和負責人類**。由于在備忘錄中存儲的是原發(fā)器的中間狀態(tài),因此需要防止原發(fā)器以外的其他對象訪問備忘錄,特別是不允許其他對象來修改備忘錄。
在使用備忘錄模式時,首先應該存在一個原發(fā)器類Originator,在真實業(yè)務中,原發(fā)器類是一個具體的業(yè)務類,它包含一些用于存儲成員數(shù)據(jù)的屬性,典型代碼如下所示:
package dp.memento;
public class Originator {
private String state;
public Originator(){}
// 創(chuàng)建一個備忘錄對象
public Memento createMemento() {
return new Memento(this);
}
// 根據(jù)備忘錄對象恢復原發(fā)器狀態(tài)
public void restoreMemento(Memento m) {
state = m.state;
}
public void setState(String state) {
this.state=state;
}
public String getState() {
return this.state;
}
}
對于備忘錄類Memento而言,它通常提供了與原發(fā)器相對應的屬性(可以是全部,也可以是部分)用于存儲原發(fā)器的狀態(tài),典型的備忘錄類設(shè)計代碼如下:
package dp.memento;
//備忘錄類,默認可見性,包內(nèi)可見
class Memento {
private String state;
public Memento(Originator o) {
state = o.getState();
}
public void setState(String state) {
this.state=state;
}
public String getState() {
return this.state;
}
}
在設(shè)計備忘錄類時需要考慮其封裝性,除了Originator類,不允許其他類來調(diào)用備忘錄類Memento的構(gòu)造函數(shù)與相關(guān)方法,如果不考慮封裝性,允許其他類調(diào)用setState()等方法,將導致在備忘錄中保存的歷史狀態(tài)發(fā)生改變,通過撤銷操作所恢復的狀態(tài)就不再是真實的歷史狀態(tài),備忘錄模式也就失去了本身的意義。
在使用Java語言實現(xiàn)備忘錄模式時,一般通過將Memento類與Originator類定義在同一個包(package)中來實現(xiàn)封裝,在Java語言中可使用默認訪問標識符來定義Memento類,即保證其包內(nèi)可見。只有Originator類可以對Memento進行訪問,而限制了其他類對Memento的訪問。在 Memento中保存了Originator的state值,如果Originator中的state值改變之后需撤銷,可以通過調(diào)用它的restoreMemento()方法進行恢復。
對于負責人類Caretaker,它用于保存?zhèn)渫泴ο螅⑻峁ゞetMemento()方法用于向客戶端返回一個備忘錄對象,原發(fā)器通過使用這個備忘錄對象可以回到某個歷史狀態(tài)。典型的負責人類的實現(xiàn)代碼如下:
package dp.memento;
public class Caretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento=memento;
}
}
在Caretaker類中不應該直接調(diào)用Memento中的狀態(tài)改變方法,它的作用僅僅用于存儲備忘錄對象。將原發(fā)器備份生成的備忘錄對象存儲在其中,當用戶需要對原發(fā)器進行恢復時再將存儲在其中的備忘錄對象取出。