標籤:java 備忘錄模式 設計模式
又名快照模式或者token模式
備忘錄對象是一個用來儲存另一個對象內部狀態的快照(snapshot)的對象。備忘錄模式用意是在不破壞封裝的條件下,將下一個對象的狀態捕捉(capture),並外部化(externalize),儲存起來,從而可以在將來合適的時候把這個對象還原到儲存起來的狀態。備忘錄模式常常與命令模式和迭代子模式一起使用。
備忘錄模式涉及的角色:備忘錄角色、發起人角色、負責人角色
備忘錄角色(Memento):
1、將發起人(Originator)對象的內部狀態儲存起來。備忘錄可以根據發起人對象的判斷來決定儲存多少發起人對象的內部狀態
2、備忘錄可以保護其內容不被發起人對象之外的任何對象所讀取。
兩個等效的介面
窄介面:負責人(Caretaker)對象看到的備忘錄的窄介面,這個窄介面只允許他把備忘錄對象傳給其他對象
寬介面:與負責人對象看到的窄介面相反的是,發起人可以可以看到一個寬介面,這個寬介面允許他讀取所有資料,以便根據這些資料恢複發起人對象的內部狀態。
發起人角色(Originator):
1、建立一個含有當前內部狀態的備忘錄對象
2、使用備忘錄Object Storage Service其內部狀態
負責人角色(Caretaker):
1、負責儲存備忘錄對象
2、不檢查備忘錄對象的內容
一、備忘錄模式的白箱實現
如所示,示意性的“白箱實現”
發起人利用新建立的備忘錄對象將自己的內部狀態儲存起來,代碼如下:
public class Originator { private String state; /** * Factory 方法,返還一個新的備忘錄對象 * factory method,return a new Memento Object * @author 付玉偉 * @time 2015-5-9 下午07:10:13 * @return */ public Memento createMemento(){ return new Memento(); } /** * 將發起人恢複到備忘錄對象所記載的狀態 * retrieve originator to status of storing in Memento * @author 付玉偉 * @time 2015-5-9 下午07:11:45 * @param memento */ public void restoreMemento(Memento memento){ this.state = memento.getState(); } public String getState() { return state; } public void setState(String state) { this.state = state; System.out.println("current state is:"+this.state); }}
下面是備忘錄角色的原始碼,備忘錄對象將發起人對象傳入狀態儲存起來。備忘錄角色會根據發起人對象的判斷類決定將發起人的內部狀態的多少儲存起來。
public 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; }}
下面是負責人角色的源碼
public class Caretaker { private Memento memento; /** * 備忘錄的取值方法 * get value of Memento * @author 付玉偉 * @time 2015-5-9 下午07:21:34 * @return */ public Memento retrieveMemento(){ return this.memento; } /** * 備忘錄的賦值方法 * set value of Memento * @author 付玉偉 * @time 2015-5-9 下午07:22:41 * @param memento */ public void saveMemento(Memento memento){ this.memento = memento; }}
下面給出一個示意性的用戶端代碼:
public class Client { private static Originator o = new Originator(); private static Caretaker c = new Caretaker(); public static void main(String[] args) { // change status of originator o.setState("On"); // create Memento Object and save status Of originator c.saveMemento(o.createMemento()); // change status of originator o.setState("Off"); // retrieve status of originator o.restoreMemento(c.retrieveMemento()); }}
白箱實現的時序圖:
系統啟動並執行時序是這樣的:
1、將發起人對象狀態設定為on
2、調用發起人角色的createMemento方法,建立一個備忘錄對象,將這個狀態儲存起來
3、將備忘錄Object Storage Service到負責人對象中
將發起人對象恢複到備忘錄對象所記錄的狀態的時序圖如下:
將發起人對象恢複備忘錄對象所記錄的狀態系統啟動並執行時序:
1、將發起人對象狀態設定為off
2、將備忘錄對象從負責人對象中取出來
3、將發起人對象恢複到備忘錄對象所儲存的狀態,即on
白箱實現的優缺點:
優點:簡單
缺點:破壞對發起人狀態的封裝
二、備忘錄模式的黑箱實現
使用內部類實現黑箱模式的的類圖如下:
在Originator類中 定義了一個內部的Memento類,由於Memento類的全部介面都是私人的,因此只有他自己和發起人可以調用。負責人角色Caretaker類的原始碼可以看到,負責人角色能夠得到備忘錄對象是以MementoIF為介面的,由於這個介面僅僅是一個標識介面,因此負責人角色不可能改變這個備忘錄對象的內容。
源碼如下:
public class Originator { private String state; public Originator(){} public MementoIF createMemento(){ return new Memento(this.state); } /** * 將發起人恢複到備忘錄記錄的狀態 * @author 付玉偉 * @time 2015-5-12 下午09:59:02 * @param memento */ public void resotreMemento(MementoIF memento){ Memento aMemento = (Memento)memento; this.setState(aMemento.getState()); } public String getState() { return state; } public void setState(String state) { this.state = state; }
protected class Memento implements MementoIF{ private String savedState; Memento(String someState){ this.savedState = someState; } public String getState() { return savedState; } public void setState(String someState) { this.savedState = someState; } }}
public class Caretaker { private MementoIF memento; /** * 備忘錄的取值方法 * @author 付玉偉 * @time 2015-5-12 下午10:04:51 * @return */ public MementoIF retrieveMemento(){ return this.memento; } /** * 備忘錄的賦值方法 * @author 付玉偉 * @time 2015-5-12 下午10:05:25 * @param memento */ public void saveMemento(MementoIF memento){ this.memento = memento; }}
public interface MementoIF {}
public class Client { /** * @author 付玉偉 * @time 2015-5-12 下午10:05:49 * @param args */ public static void main(String[] args) { Originator o = new Originator(); Caretaker c = new Caretaker(); // 改變負責人狀態 o.setState("on"); // 建立備忘錄對象,並將發起人狀態儲存起來 c.saveMemento(o.createMemento()); // 修改發起人對象的狀態 o.setState("off"); // 恢複發起人的狀態 o.resotreMemento(c.retrieveMemento()); System.out.println(o.getState()); }}
備忘錄模式的應用
1、JDBC與資料庫
在架構設計的時候都必須注意將商業邏輯與儲存邏輯分割開來原因如下:
a.兩者分開可以交給不同的設計師,便於系統維護
b.商業邏輯變化儲存邏輯不一定變
c.儲存邏輯變化商業邏輯不一定變
2、J2EE架構中備忘錄模式的應用
Cookie、URL改寫、HTML的隱藏表等
3、系統設定檔
Java設計模式——備忘錄模式(Memento)