行爲模式---之--備忘錄模式

備忘錄模式又叫快照模式(Snapshot Pattern)或Token模式,是對象的行爲模式。
 
備忘錄對象是一個用來存儲另一個對象內部狀態的快照的對象。備忘錄模式的用意是在不破壞封裝的條件下,將一個對象的狀態捕捉住,並外部化(Externalize),存儲起來,從而能夠在未來合適的時候把這個對象還原到存儲起來的狀態。它經常與命令模式和迭代子模式一同使用。
 
常見的軟件系統每每不止存儲一個狀態,而是須要存儲多個狀態。這些狀態經常是一個對象歷史發展的不一樣階段的快照,存儲這些快照的備忘錄對象叫作此對象的歷史:某一個快照所處的位置叫作檢查點(Check Point)
 
備忘錄模式涉及三個角色:
備忘錄(Memento)角色:將發起人對象的內部狀態存儲起來。備忘錄能夠根據發起人對象的
判斷來決定存儲多少發起人對象的內部狀態。備忘錄能夠保護其內容不被髮起人對象以外的任何對象讀取備忘錄有兩個等效的接口:1.窄接口:負責人對象(和其餘除發起人對象以外的任何對象)看到的是備忘錄的窄接口,這個窄接口只容許它把備忘錄對象傳給其餘的對象。2.寬接口:與負責人對象看到的窄接口相反的是,發起人對象能夠看到一個寬接口,這個寬接口容許它讀取全部的數據,以便根據這些數據恢復這個發起人的內部狀態
 
發起人(Originator)角色:它有以下責任:1.建立一個含有當前的內部狀態的備忘錄對象2.使用備忘錄對象存儲其內部狀態
負責人(Caretaker)角色:它有以下責任:1.負責保存備忘錄對象。2.不檢查備忘錄對象的內容。
 
備忘錄模式與白箱實現:
在java語言中實現備忘錄模式時,實現「寬」和「窄」兩個接口並非容易的事。若是暫時忽略兩個接口的區別,僅爲備忘錄角色提供一個寬接口的話,狀況就變得簡單得多,可是因爲備忘錄角色對象任何對象都提供一個接口,即寬接口,備忘錄角色的內部所存儲的狀態就對全部對象公開。所以這個實現又叫作「白箱實現」。「白箱」實現將發起人角色的狀態存儲在一個你們都看獲得的地方,所以是破壞封裝性的。可是經過程序員的自律,一樣能夠在必定程序上實現模式的大部分用意。它又叫作「白箱」備忘錄模式
示例代碼:
 1 public class Client {
 2     private static Originator o = new Originator();
 3     private static Caretaker c = new Caretaker();
 4     public static void main(String[] args) {
 5         //改變發起人的對象狀態
 6         o.setState("On");
 7         //建立備忘錄對象,並將發起人對象的狀態存儲起來
 8         c.saveMemento(o.createMemento());
 9         //修改發起人對象的狀態
10         o.setState("Off");
11         //恢復發起人的對象狀態
12         o.restoreMemento(c.retrieveMemento());
13         System.out.println(o.getSate());
14     }
15 }
16 //發起人角色,它用一個新建立的備忘錄對象將本身的內部狀態存儲起來
17 class Originator{
18     private String state;
19     //工廠方法,返還一個新的備忘錄對象
20     public Memento createMemento(){
21         return new Memento(state);
22     }
23     //將發起人恢復到備忘錄對象所記載的狀態
24     public void restoreMemento(Memento memento){
25         this.state = memento.getState();
26     }
27     //狀態的取值方法
28     public String getSate(){
29         return this.state;
30     }
31     //狀態的賦值方法
32     public void setState(String state){
33         this.state = state;
34         System.out.println("Current state =" + this.state);
35     }
36 }
37 
38 //備忘錄角色,它將發起人對象傳入的狀態存儲起來,它會根據發起人對象的判斷來決定將發起人的內部狀態的多少存儲起來
39 class Memento{
40     private String state;
41     //構造子
42     public Memento(String state){
43         this.state = state;
44     }
45     //狀態取值方法
46     public String getState(){
47         return this.state;
48     }
49     //狀態的賦值方法
50     public void setState(String state){
51         this.state = state;
52     }
53 }
54 //負責人角色,它負責保存備忘錄對象,但不修改備忘錄對象內容(一個更好實現是負責人對象根本沒法從備忘錄對象中讀取和修改其內容)
55 class Caretaker{
56     private Memento memento;
57     //備忘錄的取值方法
58     public Memento retrieveMemento(){
59         return this.memento;
60     }
61     //備忘錄的賦值方法
62     public void saveMemento(Memento memento){
63         this.memento = memento;
64     }
65 }

 

備忘錄模式的黑箱實現:
對於Java語言而言,能夠將Memento設成Originator類的內部類,從而將Memento對象封裝在Originator裏面,在外部提供一個標識接口MementoIF給Caretaker以及其餘對象。這樣,Originator類看到的是Memento的全部接口,而Caretaker以及其餘對象看到的僅僅是標識接口MementoIF所暴露出來的接口。
示例代碼:
 1 public class Client {
 2     private static Originator o = new Originator();
 3     private static Caretaker c = new Caretaker();
 4     public static void main(String[] args) {
 5         //改變發起人的對象狀態
 6         o.setState("On");
 7         //建立備忘錄對象,並將發起人對象的狀態存儲起來
 8         c.saveMemento(o.createMemento());
 9         //修改發起人對象的狀態
10         o.setState("Off");
11         //恢復發起人的對象狀態
12         o.restoreMemento(c.retriveMemento());
13         System.out.println(o.getState());
14     }
15 }
16 //發起人角色,在此類中定義了一個內部的Memento類,因爲此類的全部方法都是私有的,所以只有它本身和發起人(Originator)類能夠調用
17 class Originator{
18     private String state;
19     //構造
20     public Originator(){}
21     //工廠方法,返還一個新的備忘錄對象
22     public MementoIF createMemento(){
23         return new Memento(this.state);
24     }
25     //將發想人恢復到備忘錄對象記錄的狀態
26     public void restoreMemento(MementoIF memento){
27         Memento aMemento = (Memento)memento;
28         this.setState(aMemento.getState());
29     }
30     //狀態的取值方法
31     public String getState(){
32         return this.state;
33     }
34     //狀態的賦值方法
35     public void setState(String state){
36         this.state = state;
37         System.out.println("state ="+ state);
38     }
39     //內部成員類,備忘錄
40     protected class Memento implements MementoIF{
41         private String savedState;
42         //構造
43         private Memento(String someState){
44             savedState = someState;
45         }
46         //狀態賦值方法
47         private void setState(String someState){
48             savedState = someState;
49         }
50         //狀態取值方法
51         private String getState(){
52             return savedState;
53         }
54     }
55 }
56 
57 //MementoIF角色只是一個標識接口,它就是窄接口,因爲它是一個標識接口,因此負責人不可能改變這個備忘錄對象 的內容 
58 interface MementoIF{}
59 
60 //負責人角色
61 class Caretaker{
62     private MementoIF memento;
63     //備忘錄的取值方法
64     public MementoIF retriveMemento(){
65         return this.memento;
66     }
67     //備忘錄的賦值方法
68     public void saveMemento(MementoIF memento){
69         this.memento = memento;
70     }
71 }

 

備忘錄模式的優勢:
1.有時一些發起人對象的內部信息必須保存在發起人對象之外的地方,可是必需要由發起人對象本身讀取。這時,使用備忘錄能夠把複雜的發起人內部信息對其餘的對象屏蔽起來,從而能夠恰當地保持封裝的邊界
2.本模式簡化了發起人類。發起人再也不須要管理和保存其內部狀態的一個個版本,客戶端能夠自行管理 它們所須要的這些狀態的版本。
3.當發起人角色的狀態改變的時候,有可能這個狀態無效,這時候就可使用暫時存儲起來的備忘錄將狀態復原。
備忘錄模式的缺點:
1.若是發起人角色的狀態須要完整地存儲到備忘錄對象中,那麼在資源消耗上面備忘錄對象會很昂貴
2.當負責人角色將一個備忘錄存儲起來的時候,負責人可能並不知道這個狀態會佔用多大的存儲空間,從而沒法提醒用戶一個操做是否會很昂貴。
3.當發起人角色的狀態改變的時候,有可能這個狀態無效。
相關文章
相關標籤/搜索