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