定義:在不破壞封裝性的前提下,捕獲一個對象的内部狀态,并在該對象之外儲存這個狀态。這樣以後就可将
該對象恢複到原先儲存的狀态。
一般模式:

Originator發起人角色
---|記錄目前時刻的内部狀态,負責定義那些屬于備份範圍的狀态,負責建立和恢複備忘錄資料
Memento備忘錄角色
---|負責存儲Originator發起人對象的内部狀态,在需要的時候提供發起人需要的内部狀态
Caretaker備忘錄管理者角色
---|對備忘錄進行管理、儲存和提供備忘錄。
public class MementoTest {
public static void main(String[] args) {
//定義一個備忘錄的發起者
Originator origin = new Originator();
origin.setState("你好!");
//定義一個備忘錄的管理者
Caretaker care = new Caretaker();
//建立一個備忘錄
care.setMemento(origin.createMemento());
origin.setState("去死吧!");
//恢複原有的資料
origin.restoreMemento(care.getMemento());
System.out.println(origin.getState());
}
}
/**
* 備忘錄發起人的角色,
* 備忘錄中儲存的就是該類的内容。
* @author admin
*
*/
class Originator{
//一個String類型表示目前狀态
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());
}
}
/**
* 備忘錄角色,
* 該類用于備份、存儲原有資料。
* @author admin
*
*/
class Memento{
//一個String類型表示目前狀态
private String state = "";
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
/**
* 備忘錄的管理類
* 對備忘錄進行管理、儲存和存儲
* @author admin
*/
class Caretaker{
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
一個例子:
模拟月光寶盒中,至尊寶阻止白晶晶自殺的橋段。當白晶晶在洞内自殺,至尊寶沒有來得及救,于是就使用月光寶盒--鳳梨鳳梨蜜
任何就回到上一個狀态,繼續去救白晶晶,知道能夠成功救到為止。
這個例子可以說明,救白晶晶之前,首先儲存一個狀态命名為1,從這一狀态出發,如果沒有成功,就回到1狀态。
public class MementoT {
public static void main(String[] args) {
//建立一個發起者,(看見白晶晶在自殺)
SaveLifeAction action = new SaveLifeAction();
action.setState("白晶晶被至尊寶傷透了心...準備拿劍抹脖子自殺");
//月關寶盒時刻記錄每一瞬間
BoxManager boxManager = new BoxManager();
boxManager.setBoxMemento(action.createMemento());
action.setState("白晶晶自殺死了...");
System.out.println(action.getState());
System.out.println("---至尊寶拿着月關寶盒,回去救她----");
//至尊寶拿着月關寶盒,回去救她
action.restoreMemento(boxManager.getBoxMemento());
//回到上一狀态
System.out.println(action.getState());
action.setSuccess(true);
if(action.isSuccess()){
System.out.println("----白晶晶成功獲救!");
}
}
}
/**
* 該類是發起者類,
* 設定負責建立和恢複備忘錄
* @author admin
*
*/
class SaveLifeAction{
//定義一個狀态,用于描述目前正在做什麼..
private String state="";
//設定是否救成功
private boolean isSuccess;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
//建立一個備份的狀态
public BoxMemento createMemento(){
return new BoxMemento(this.state);
}
//恢複到原來的狀态
public void restoreMemento(BoxMemento boxMemento){
this.setState(boxMemento.getState());
}
}
/**
* 該類是備忘錄類
* 相當于故事中的月光寶盒,他帶你回到上一個狀态。
* 内部實作的原理就是,儲存上一狀态而已。
* @author admin
*
*/
class BoxMemento{
private String state="";
public BoxMemento(String state) {
this.state = state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
/**
* 備忘錄的管理者,
* 誰拿到月光寶盒,誰就可以操縱月光寶盒,
* 就可以回到過去。
* @author admin
*
*/
class BoxManager{
private BoxMemento boxMemento;
public BoxMemento getBoxMemento() {
return boxMemento;
}
public void setBoxMemento(BoxMemento boxMemento) {
this.boxMemento = boxMemento;
}
}
備忘錄模式的使用場景
---|需要儲存和恢複資料的相關狀态場景。
---|提供一個可復原(rollback)的操作,比如word中Ctrl+Z的組合鍵。
---|需要監控的副本場景中。
---|資料庫連接配接的事務管理就是用的備忘錄模式。
備忘錄的擴充
---|1、實作java類中的Cloneable實作備忘錄模式
使用clone方式的備忘錄模式,可以使用在比較簡單的場景或者比較單一的場景中,
盡量不要與其他的對象産生嚴重的耦合關系。
public class MementoExpand {
public static void main(String[] args) {
//定義一個發起人
OriginClass origin = new OriginClass();
origin.setState("我的原始狀态");
//建立備份
origin.createOrigin();
origin.setState("我的現在狀态..");
System.out.println(origin.getState());
System.out.println("------我不喜歡現在的狀态-------");
//恢複原來的狀态
origin.restoreOrigin();
System.out.println(origin.getState());
}
}
/**
* 發起者實作Cloneable接口,完成自身的備忘錄設定。
* 無需接觸其他類來儲存自身的目前狀态。
* @author admin
*
*/
class OriginClass implements Cloneable{
private String state;
//自身的備忘錄角色
private OriginClass backUp;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
//建立備份
public void createOrigin(){
this.backUp = (OriginClass) this.clone();
}
//恢複原來的資訊
public void restoreOrigin(){
this.setState(backUp.getState());
}
@Override
protected Object clone() {
try {
return (OriginClass) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
---|2多狀态的備忘錄模式
/**
* 通過java.beans.Introspector類擷取其他類中的屬性和方法
* @author admin
*
*/
public class BeanUtil {
public static void main(String[] args) {
//建立一個發起者
MyOringin origin = new MyOringin("lzl",10000,"程式員");
System.out.println("在百度公司裡:"+origin.toString());
//在百度公司建立備份
MyMementor mementor = origin.createMemento();
System.out.println("感覺太累了,跳槽的阿裡巴巴...");
origin.setName("lzl");
origin.setPosition("程式員");
origin.setSalary(12000);
System.out.println("跳槽到阿裡:"+origin.toString());
System.out.println("----------------在這裡更累,跟着老大,10天沒合眼...想回到百度了.");
origin.restoreMemento(mementor);
System.out.println("回到百度,還是很輕松的。。"+origin.toString());
}
//擷取發起者類中的屬性參數,并儲存在hashMap中
public static HashMap<String, Object> backUpProp(Object bean){
HashMap<String, Object> result = new HashMap<String, Object>();
//獲得Bean描述
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
//傳回PropertyDescriptor類型的javaBean描述
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
//周遊傳回的javaBean
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;
}
//把HashMap中的值設定到bean中。
public static void restoreProp(Object bean,HashMap<String, Object> propMap){
//擷取BeanInfo
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
//擷取PropertyDescriptor的對象數組
PropertyDescriptor[] descripors = beanInfo.getPropertyDescriptors();
//增強for循環,周遊所有的屬性,設定到bean中
for(PropertyDescriptor des : descripors){
//擷取key值對象
String fieldName = des.getName();
//如果包含這個屬性
if(propMap.containsKey(fieldName)){
//擷取屬性set的方法
Method setter = des.getWriteMethod();
setter.invoke(bean, new Object[]{propMap.get(fieldName)});
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 類的發起者,模拟擁有多個屬性。
* @author admin
*
*/
class MyOringin{
//姓名
private String name;
//薪水
private double salary;
//職位
private String position;
public MyOringin(String name,double salary,String position) {
this.name = name;
this.salary = salary;
this.position = position;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
//建立一個備份
public MyMementor createMemento(){
//将方法屬性存儲到BeanUtil.backUpProp()中的hashMap中
return new MyMementor(BeanUtil.backUpProp(this));
}
public void restoreMemento(MyMementor memento){
BeanUtil.restoreProp(this, memento.getBeanMap());
}
@Override
public String toString() {
return "姓名:"+this.name+"\t職位:"+this.position
+"\t薪水:"+this.salary+"\t";
}
}
/**
* 備忘錄類,用于儲存原有的狀态。
* @author admin
*/
class MyMementor{
//定義一個hashMap來接收發起者的所有屬性狀态備份
private HashMap<String, Object> beanMap = new HashMap<String, Object>();
public MyMementor(HashMap<String, Object> beanMap) {
this.beanMap = beanMap;
}
public HashMap<String, Object> getBeanMap() {
return this.beanMap;
}
public void setBeanMap(HashMap<String, Object> beanMap) {
this.beanMap = beanMap;
}
}