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恢复等。

相关文章
相关标签/搜索