定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象以外保存这个状态。这样就能够将该对象恢复到原先保存的状态 java
类型:行为类 编程
类图: 设计模式
咱们在编程的时候,常常须要保存对象的中间状态,当须要的时候,能够恢复到这个状态。好比,咱们使用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恢复等。