23種設計模式(15):備忘錄模式

定義:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態。這樣就能夠將該對象恢復到原先保存的狀態 java

類型:行爲類 編程

類圖: 設計模式

23種設計模式(15):備忘錄模式 - 第1張  | 快課網

咱們在編程的時候,常常須要保存對象的中間狀態,當須要的時候,能夠恢復到這個狀態。好比,咱們使用Eclipse進行編程時,假如編寫失誤(例如不當心誤刪除了幾行代碼),咱們但願返回刪除前的狀態,即可以使用Ctrl+Z來進行返回。這時咱們即可以使用備忘錄模式來實現。 架構

 

備忘錄模式的結構 編輯器

  • 發起人:記錄當前時刻的內部狀態,負責定義哪些屬於備份範圍的狀態,負責建立和恢復備忘錄數據。
  • 備忘錄:負責存儲發起人對象的內部狀態,在須要的時候提供發起人須要的內部狀態。
  • 管理角色:對備忘錄進行管理,保存和提供備忘錄。

 

通用代碼實現 this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class Originator {
     private String state = "" ;
 
     public String getState ( ) {
         return state ;
     }
     public void setState ( String state ) {
         this . state = state ;
     }
     public Memento createMemento ( ) {
         return new Memento ( this . state ) ;
     }
     public void restoreMemento ( Memento memento ) {
         this . setState ( memento . getState ( ) ) ;
     }
}
 
class Memento {
     private String state = "" ;
     public Memento ( String state ) {
         this . state = state ;
     }
     public String getState ( ) {
         return state ;
     }
     public void setState ( String state ) {
         this . state = state ;
     }
}
class Caretaker {
     private Memento memento ;
     public Memento getMemento ( ) {
         return memento ;
     }
     public void setMemento ( Memento memento ) {
         this . memento = memento ;
     }
}
public class Client {
     public static void main ( String [ ] args ) {
         Originator originator = new Originator ( ) ;
         originator . setState ( "狀態1" ) ;
         System . out . println ( "初始狀態:" + originator . getState ( ) ) ;
         Caretaker caretaker = new Caretaker ( ) ;
         caretaker . setMemento ( originator . createMemento ( ) ) ;
         originator . setState ( "狀態2" ) ;
         System . out . println ( "改變後狀態:" + originator . getState ( ) ) ;
         originator . restoreMemento ( caretaker . getMemento ( ) ) ;
         System . out . println ( "恢復後狀態:" + originator . getState ( ) ) ;
     }
}

 

代碼演示了一個單狀態單備份的例子,邏輯很是簡單:Originator類中的state變量須要備份,以便在須要的時候恢復;Memento類中,也有一個state變量,用來存儲Originator類中state變量的臨時狀態;而Caretaker類就是用來管理備忘錄類的,用來向備忘錄對象中寫入狀態或者取回狀態。 spa

 

多狀態多備份備忘錄 設計

通用代碼演示的例子中,Originator類只有一個state變量須要備份,而一般狀況下,發起人角色一般是一個javaBean,對象中須要備份的變量不止一個,須要備份的狀態也不止一個,這就是多狀態多備份備忘錄。實現備忘錄的方法不少,備忘錄模式有不少變形和處理方式,像通用代碼那樣的方式通常不會用到,多數狀況下的備忘錄模式,是多狀態多備份的。其實實現多狀態多備份也很簡單,最經常使用的方法是,咱們在Memento中增長一個Map容器來存儲全部的狀態,在Caretaker類中一樣使用一個Map容器才存儲全部的備份。下面咱們給出一個多狀態多備份的例子: rest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
class Originator {
     private String state1 = "" ;
     private String state2 = "" ;
     private String state3 = "" ;
 
     public String getState1 ( ) {
         return state1 ;
     }
     public void setState1 ( String state1 ) {
         this . state1 = state1 ;
     }
     public String getState2 ( ) {
         return state2 ;
     }
     public void setState2 ( String state2 ) {
         this . state2 = state2 ;
     }
     public String getState3 ( ) {
         return state3 ;
     }
     public void setState3 ( String state3 ) {
         this . state3 = state3 ;
     }
     public Memento createMemento ( ) {
         return new Memento ( BeanUtils . backupProp ( this ) ) ;
     }
 
     public void restoreMemento ( Memento memento ) {
         BeanUtils . restoreProp ( this , memento . getStateMap ( ) ) ;
     }
     public String toString ( ) {
         return "state1=" + state1 + "state2=" + state2 + "state3=" + state3 ;
     }
}
class Memento {
     private Map < String , Object > stateMap ;
 
     public Memento ( Map < String , Object > map ) {
         this . stateMap = map ;
     }
 
     public Map < String , Object > getStateMap ( ) {
         return stateMap ;
     }
 
     public void setStateMap ( Map < String , Object > stateMap ) {
         this . stateMap = stateMap ;
     }
}
class BeanUtils {
     public static Map < String , Object > backupProp ( Object bean ) {
         Map < String , Object > result = new HashMap < String , Object > ( ) ;
         try {
             BeanInfo beanInfo = Introspector . getBeanInfo ( bean . getClass ( ) ) ;
             PropertyDescriptor [ ] descriptors = beanInfo . getPropertyDescriptors ( ) ;
             for ( PropertyDescriptor des : descriptors ) {
                 String fieldName = des . getName ( ) ;
                 Method getter = des . getReadMethod ( ) ;
                 Object fieldValue = getter . invoke ( bean , new Object [ ] { } ) ;
                 if ( ! fieldName . equalsIgnoreCase ( "class" ) ) {
                     result . put ( fieldName , fieldValue ) ;
                 }
             }
 
         } catch ( Exception e ) {
             e . printStackTrace ( ) ;
         }
         return result ;
     }
 
     public static void restoreProp ( Object bean , Map < String , Object > propMap ) {
         try {
             BeanInfo beanInfo = Introspector . getBeanInfo ( bean . getClass ( ) ) ;
             PropertyDescriptor [ ] descriptors = beanInfo . getPropertyDescriptors ( ) ;
             for ( PropertyDescriptor des : descriptors ) {
                 String fieldName = des . getName ( ) ;
                 if ( propMap . containsKey ( fieldName ) ) {
                     Method setter = des . getWriteMethod ( ) ;
                     setter . invoke ( bean , new Object [ ] { propMap . get ( fieldName ) } ) ;
                 }
             }
         } catch ( Exception e ) {
             e . printStackTrace ( ) ;
         }
     }
}
class Caretaker {
     private Map < String , Memento > memMap = new HashMap < String , Memento > ( ) ;
     public Memento getMemento ( String index ) {
         return memMap . get ( index ) ;
     }
 
     public void setMemento ( String index , Memento memento ) {
         this . memMap . put ( index , memento ) ;
     }
}
class Client {
     public static void main ( String [ ] args ) {
         Originator ori = new Originator ( ) ;
         Caretaker caretaker = new Caretaker ( ) ;
         ori . setState1 ( "中國" ) ;
         ori . setState2 ( "強盛" ) ;
         ori . setState3 ( "繁榮" ) ;
         System . out . println ( "===初始化狀態===\n" + ori ) ;
 
         caretaker . setMemento ( "001" , ori . createMemento ( ) ) ;
         ori . setState1 ( "軟件" ) ;
         ori . setState2 ( "架構" ) ;
         ori . setState3 ( "優秀" ) ;
         System . out . println ( "===修改後狀態===\n" + ori ) ;
 
         ori . restoreMemento ( caretaker . getMemento ( "001" ) ) ;
         System . out . println ( "===恢復後狀態===\n" + ori ) ;
     }
}

 

備忘錄模式的優缺點和適用場景 對象

備忘錄模式的優勢有:

  • 當發起人角色中的狀態改變時,有可能這是個錯誤的改變,咱們使用備忘錄模式就能夠把這個錯誤的改變還原。
  • 備份的狀態是保存在發起人角色以外的,這樣,發起人角色就不須要對各個備份的狀態進行管理。

備忘錄模式的缺點:

  • 在實際應用中,備忘錄模式都是多狀態和多備份的,發起人角色的狀態須要存儲到備忘錄對象中,對資源的消耗是比較嚴重的。

若是有須要提供回滾操做的需求,使用備忘錄模式很是適合,好比jdbc的事務操做,文本編輯器的Ctrl+Z恢復等。

相關文章
相關標籤/搜索