定義:
- 在不破壞封裝性的前提下妓灌,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài)琅摩,并在該對(duì)象之外保存這個(gè)狀態(tài)厅各,這樣以后就可將該對(duì)象恢復(fù)到原先保存的狀態(tài)盗蟆。
備忘錄模式的通用類圖:
/*
* 定義備忘錄角色
* */
public class Memento {
// 發(fā)起人的內(nèi)部角色
private String state = "";
public Memento(String state) {
// TODO Auto-generated constructor stub
this.state = state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
/*
* 創(chuàng)建備忘錄管理者
* */
public class Caretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
/*
* 定義發(fā)起人
* */
public class Originator {
// 內(nèi)部狀態(tài)
private String state = "";
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
// 創(chuàng)建備忘錄
public Memento createMemento() {
return new Memento(this.state);
}
// 重新存儲(chǔ)
public void restoreMemento(Memento memento) {
this.setState(memento.getState());
}
}
public class Client {
public static void main(String[] args) {
// 定義發(fā)起人
Originator originator = new Originator();
// 創(chuàng)建備忘錄管理者
Caretaker caretaker = new Caretaker();
// 創(chuàng)建備忘錄
caretaker.setMemento(originator.createMemento());
// 恢復(fù)備忘錄
originator.restoreMemento(caretaker.getMemento());
}
}
使用場(chǎng)景
- 需要保存和恢復(fù)數(shù)據(jù)的相關(guān)狀態(tài)場(chǎng)景戈二。
- 提供一個(gè)可回滾(rollback)的操作
- 需要監(jiān)控的副本場(chǎng)景中。備份一個(gè)主線程中的對(duì)象喳资,然后由分析程序來(lái)分析
- 數(shù)據(jù)庫(kù)連接的事務(wù)管理就是用的備忘錄模式
注意事項(xiàng):
- 備忘錄的生命周期:創(chuàng)建出來(lái)后觉吭,要在"最近"的代碼中使用,要主動(dòng)管理它的生命周期仆邓,建立就要使用鲜滩,不是用就要立刻刪除,等待垃圾回收器對(duì)它的回收處理节值。
- 備忘錄的性能:不要再頻繁建立備份的場(chǎng)景中使用備忘錄模式(for循環(huán))徙硅,一是控制不了備忘錄建立的對(duì)象數(shù)量,二是大對(duì)象的建立是要消耗資源的搞疗,影響性能嗓蘑。
備忘錄模式拓展:
public class Caretaker {
private Originator originator;
public Originator getOriginator() {
return originator;
}
public void setOriginator(Originator originator) {
this.originator = originator;
}
}
public class Originator implements Cloneable {
// 將發(fā)起者和備忘錄角色進(jìn)行合并
private String state = "";
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
// 創(chuàng)建備忘錄角色
public Originator createMemento() {
return this.clone();
}
// 恢復(fù)備忘錄角色
public void restoreMemento(Originator _originator) {
this.setState(_originator.getState());
}
@Override
protected Originator clone() {
// TODO Auto-generated method stub
try {
return (Originator) super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
/*
* 去掉管理員角色,精簡(jiǎn)
* 設(shè)計(jì)模式定義的誕生比JAVA的出世略早贴汪,沒(méi)有想到
* java在面向?qū)ο蟮脑O(shè)計(jì)中脐往,可以實(shí)現(xiàn)把一個(gè)類封裝在另一個(gè)類中
* */
public class OriginatorMix implements Cloneable {
private OriginatorMix originatorMix;
private String state = "";
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public void setMemento() {
originatorMix = this.clone();
}
public void restoreMemento() {
this.setState(this.originatorMix.getState());
}
@Override
protected OriginatorMix clone() {
// TODO Auto-generated method stub
try {
return (OriginatorMix) super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
public class Cient {
public static void main(String[] args) {
//使用clone方式一實(shí)現(xiàn)
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
caretaker.setOriginator(originator);//備份
originator.restoreMemento(caretaker.getOriginator());//恢復(fù)
//使用clone方式二實(shí)現(xiàn)
OriginatorMix originatorMix = new OriginatorMix();
System.out.println("init");
originatorMix.setState("初始狀態(tài)");
System.out.println(originatorMix.getState());
System.out.println("memento");
originatorMix.setMemento();
originatorMix.setState("備份后的狀態(tài)");
System.out.println(originatorMix.getState());
originatorMix.restoreMemento();
System.out.println("recover memento");
System.out.println(originatorMix.getState());
}
}
發(fā)起人角色融合了發(fā)起人角色和備忘錄角色,具有雙重功效扳埂。使用clone方式的備忘錄业簿,可以使用在比較簡(jiǎn)單的場(chǎng)景或者比較單一的場(chǎng)景中,盡量不要與其他的對(duì)象產(chǎn)生嚴(yán)重的耦合關(guān)系阳懂。對(duì)于深拷貝梅尤,考慮對(duì)應(yīng)的語(yǔ)句書寫。
/*
* 定義備忘錄角色
* */
public class Memento {
// 接受HashMap作為備份狀態(tài)
private HashMap<String, Object> hashMap;
public HashMap<String, Object> getStateMap() {
return hashMap;
}
public void setHashMap(HashMap<String, Object> hashMap) {
this.hashMap = hashMap;
}
// 接收一個(gè)對(duì)象岩调,建立一個(gè)備份
public Memento(HashMap<String, Object> hashMap) {
// TODO Auto-generated constructor stub
this.hashMap = hashMap;
}
}
public class Originator {
// 內(nèi)部狀態(tài)
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;
}
// 創(chuàng)建一個(gè)備忘錄
public Memento createMemo() {
return new Memento(BeanUtils.backupProp(this));
}
// 恢復(fù)一個(gè)備忘錄
public void restoreMemento(Memento _memento) {
BeanUtils.restoreProp(this, _memento.getStateMap());
}
// 增加 toString
@Override
public String toString() {
// TODO Auto-generated method stub
return "state1=" + state1 + "state2=" + state2 + "state3=" + state3;
}
}
/*
* 創(chuàng)建備忘錄管理者
* */
public class Caretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
public class BeanUtils {
// 把bean的所有屬性及數(shù)值放入到Hashmap中
public static HashMap<String, Object> backupProp(Object bean) {
HashMap<String, Object> result = new HashMap<>();
try {
// 獲取Bean描述
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
// 獲取相關(guān)的屬性描述
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
// 獲取屬性名的值
String fieldName = propertyDescriptor.getName();
// 讀取屬性的get方法
Method getter = propertyDescriptor.getReadMethod();
// 讀取屬性值
Object fieldValue = getter.invoke(bean, new Object[] {});
if (!fieldName.equalsIgnoreCase("class"))
result.put(fieldName, fieldValue);
}
} catch (IntrospectionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
// 把HashMap放到bean中
public static void restoreProp(Object bean, HashMap<String, Object> propMap) {
try {
// 獲取Bean描述
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
// 獲取相關(guān)的屬性描述
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
String fieldName = propertyDescriptor.getName();
// 判斷對(duì)應(yīng)的屬性是否存在
if (propMap.containsKey(fieldName)) {
// 寫屬性方法
Method setter = propertyDescriptor.getWriteMethod();
setter.invoke(bean, new Object[] { propMap.get(fieldName) });
}
}
} catch (Exception e) {
// 異常處理
}
}
}
public class Client {
public static void main(String[] args) {
// 定義出發(fā)起人
Originator originator = new Originator();
// 定義出備忘錄管理員
Caretaker caretaker = new Caretaker();
originator.setState1("1");
originator.setState2("2");
originator.setState3("3");
System.out.println("初始化狀態(tài):" + originator.toString());
// 創(chuàng)建備忘錄
caretaker.setMemento(originator.createMemo());
originator.setState1("6");
originator.setState2("5");
originator.setState3("4");
System.out.println("更新?tīng)顟B(tài):" + originator.toString());
// 恢復(fù)備忘錄
originator.restoreMemento(caretaker.getMemento());
System.out.println("恢復(fù)后的狀態(tài)為:" + originator.toString());
}
}
- 多備份備份
/*
* 多備份管理員巷燥,通過(guò)hashmap作為數(shù)據(jù)存儲(chǔ)的載體
* */
public class Caretaker {
// 容納備忘錄的容器
private HashMap<String, Memento> menMap = new HashMap<>();
public Memento getMemento(String idx) {
return this.menMap.get(idx);
}
// 注意內(nèi)存溢出問(wèn)題,該備份一旦產(chǎn)生就放入到內(nèi)存中号枕,沒(méi)有銷毀的意向缰揪,
// 所以在系統(tǒng)設(shè)計(jì)的時(shí)候,要嚴(yán)格限定備忘錄的創(chuàng)建葱淳。建議增加Map的上限
// 否則很容易產(chǎn)生內(nèi)存溢出的情況
public void storeMemento(String idx, Memento memento) {
this.menMap.put(idx, memento);
}
}
public class Client {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
caretaker.storeMemento("1", originator.createMemo());
caretaker.storeMemento("2", originator.createMemo());
// 恢復(fù)到指定狀態(tài)的備忘錄
originator.restoreMemento(caretaker.getMemento("2"));
}
}
- 使用內(nèi)置類實(shí)現(xiàn)備忘錄
/*
* 全部通過(guò)接口進(jìn)行訪問(wèn)钝腺,
* 如果你想訪問(wèn)它的屬性肯定是不行,
* 沒(méi)有絕對(duì)的安全赞厕,
* 通過(guò)reflect反射修改Memento的數(shù)據(jù)
* */
public class Caretaker {
private IMemento memento;
public IMemento getMemento() {
return memento;
}
public void setMemento(IMemento memento) {
this.memento = memento;
}
}
/*
* 定義空一個(gè)備忘錄接口
* */
public interface IMemento {
}
public class Originator {
// 內(nèi)部狀態(tài)
private String state = "";
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
// 創(chuàng)建備忘錄
public Memento createMemento() {
return new Memento(this.state);
}
// 重新存儲(chǔ)
public void restoreMemento(IMemento _memento) {
this.setState(((Memento) _memento).getState());
}
// 使用內(nèi)部類實(shí)現(xiàn)接口
class Memento implements IMemento {
// 發(fā)起人的內(nèi)部角色
private String state = "";
public Memento(String state) {
// TODO Auto-generated constructor stub
this.state = state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
}