熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

備忘錄模式(Memento Pattern)

2013-11-23 19:54:44  來源: Java高級技術 

  描述
  
  對象的狀態可以定義為在特定的時間點對象的屬性值備忘錄模式(Memento Pattern)應用於保存和跟蹤對象的狀態以便於必要的時候可以把對象恢復到以前的狀態它很像恢復操作備忘錄模式(Memento Pattern)可以在不暴露對象的內部結構的情況下完成這樣的功能需要獲取以前狀態的對象就是指發起者(Originator)當客戶需要保存發起者的狀態時客戶需要發起者的當前狀態發起者存貯所有保持它狀態的屬性到一個獨立的對象這個對象就是備忘錄(紀念記憶)Memento把備忘錄(Memento)對象返回給客戶備忘錄(Memento)對象可以看作在給定的時間點包含另一個對象內部狀態的對象備忘錄(Memento)對象必須向除了發起者以外的所有對象隱藏發起者變量的值當發起者允許備忘錄(Memento)對象訪問它的內部狀態時備忘錄(Memento)對象應該被設計為對其他對象采取訪問限制的對象
  
  當客戶需要把發起者的狀態恢復到以前的狀態時它只是簡單的把備忘錄(Memento)對象返回給發起者發起者使用包含在備忘錄(Memento)對象中的狀態信息恢復自己到備忘錄(Memento)對象中保存的狀態
  
  例子
  
  數據轉化(Data conversion)總是那些涉及到從遺留系統轉化到應用新技術的系統不可缺少的一部分讓我們假定一個需要把客戶數據從文本文件移植到關系型數據庫中的類似應用程序在將客戶數據發送給數據庫以前要對客戶紀錄進行驗證
  
  現實中客戶紀錄需要包括很多屬性但是為了簡單讓我們假定每一個客戶紀錄只有三個屬性??first namelast name和credit card number驗證過程也很簡單只要last name不為空而且credit card number(信用卡號)僅有的數字組成當發現一個無效的客戶記錄時驗證過程需要停止提示用戶修正數據並重新開始在這個時間點上數據轉化(Data conversion)過程的狀態需要保存在一個備忘錄(Memento)對象內部當用戶重新開始驗證過程時數據裝化過程從保存在備忘錄(Memento)對象中的狀態開始驗證過程從它停止的地方恢復而不是從原數據起點重新開始通常備忘錄(Memento)對象既可以保存在內存中也可以保存在持久介質上在這個應用中當應用被打斷以後狀態需要保存而且當應用再次運行的時候需要恢復因此在這種情況下不適於把備忘錄(Memento)對象保存在內存中而是需要保存在持久介質上
  
  不是直接把合法的客戶紀錄插入到關系數據庫中應用程序而是生成一個由SQL插入語句組成的文本文件執行這些SQL語句可以把數據插入到數據庫中
  
  讓我們為這個驗證過程設計不同的組件
  
  DataConverter(發起者)
  
  DataConverter類(圖和Listing)是數據轉化過程的實現
  
 
  Figure : DataConverter Class?The Originator
  

  Listing : DataConverter Class
  
  public class DataConverter {
  public static final String DATA_FILE = Datatxt;
  public static final String OUTPUT_FILE = SQLtxt;
  private long ID = ;
  public Memento createMemento() {
  return (new Memento(ID));
  }
  public void setMemento(Memento memento) {
  if (memento != null)
  ID = mementogetID();
  }
  public long getLastProcessedID() {
  return ID;
  }
  public void setLastProcessedID(long lastID) {
  ID = lastID;
  }
  public boolean process() {
  boolean success = true;
  String inputLine = ;
  long currID = ;
  try {
  File inFile = new File(DATA_FILE);
  BufferedReader br = new BufferedReader(
  new InputStreamReader(
  new FileInputStream(inFile)));
  long lastID = getLastProcessedID();
  while ((inputLine = brreadLine()) != null) {
  StringTokenizer st =
  new StringTokenizer(inputLine );
  String strID = stnextToken();
  currID = new Long(strID)longValue();
  if (lastID < currID) {
  Customer c =
  new Customer(strID stnextToken()
  stnextToken() stnextToken());
  if (!(cisValid())) {
  success = false;
  break;
  }
  ID = new Long(strID)longValue();
  FileUtil util = new FileUtil();
  utilwriteToFile(OUTPUT_FILE cgetSQL()
  true true);
  }
  }
  brclose();
  }//Try
  catch (Exception ex) {
  Systemoutprintln( An error has occurred +
  exgetMessage());
  Systemexit();
  }
  if (success == false) {
  Systemoutprintln(An error has occurred at ID= +
  currID);
  Systemoutprintln(Data Record= + inputLine);
  return false;
  }
  return true;
  }
  class Memento implements javaioSerializable {
  private long lastProcessedID;
  private Memento(long ID) {
  lastProcessedID = ID;
  }
  private long getID() {
  return lastProcessedID;
  }
  }//end of class
  }//end of class
  
  ID
  
  實例變量ID組成了DataConverter的狀態它代表了最後一個被成功處理的客戶紀錄的客戶ID
  
  Memento
  
  Memento定義為DataConverter的一個內部類Memento將它的構造函數和其他方法定義為私有
  
  在Java中一個類可以訪問它內部類的私有成員
  
  DataConverter可以訪問這些方法但是其他的對象不可以訪問因為當應用結束的時候DataConverter的狀態需要被保存Memento對象需要被序列化(serialize)到一個文件中因此Memento類需要實現javaioSerializable接口以表明自己是一個可序列化(Serializable)的類
  
  在JAVA中一個序列化的類必須
  
  使用transient 關鍵字明確指出不需要序列化的屬性
  實現javaioSerializable接口
  可以訪問它的第一個非序列化夫類的零參數的構造函數
  
  process
  
  process方法讀取元數據文件通過Customer helper類驗證客戶數據對於每一個有效的客戶紀錄相應的SQL插入語句被寫入到輸出文件中當遇到無效客戶紀錄時數據轉化過程停止
  
  createMemento
  
  如方法名字這個方法負責創建Memento對象它把DataConverter對象的當前狀態保存到一個Memento實例內並放回它
  
  setMemento
  
  取出輸入的Memento對象的狀態信息重新設置DataConverter的狀態到此狀態
  
  DCClient (Client)
  
  客戶DCClient(Listing )首先初始化DataConverter調用DataConverter實例的process方法開始數據轉化過程如果process方法在處理原數據文件期間遇到無效的客戶數據它會調用DataConverter實例的createMemento方法捕獲當前狀態createMemento方法返回一個Memento對象客戶DCClient使用MementoHandler對象負責序列化Memento實例到一個文件
  
  Listing : DCClient Class
  
  public class DCClient {
  public static void main(String[] args) {
  MementoHandler objMementoHandler = new MementoHandler();
  DataConverter objConverter = new DataConverter();
  objConvertersetMemento(objMementoHandlergetMemento());
  if (!(objConverterprocess())) {
  Systemoutprintln(Description: Invalid data +
  Process Stopped);
  Systemoutprintln(Please correct the Data and +
  Run the Application Again);
  objMementoHandlersetMemento(
  objConvertercreateMemento());
  }
  }
  }
  
  一旦數據被校正客戶DCClient就會再次運行
  
  客戶DCClient調用MementoHandler 上的getMemento 方法請求它保存Memento對象
  MementoHandler 從文件中反序列化以前的Memento對象並把它放回給客戶
  客戶把它作為DataConverter 的setMemento方法的參數傳遞給DataConverter DataConverter使自己返回到保存在Memento對象中的狀態從原來停止的地方恢復數據轉化過程
  
  MementoHandler
  
  The MementoHandler (Listing ) 包含了Memento 對象的一個引用客戶DCClient把一個Memento的實例傳遞給它
  
  Listing : MementoHandler Class
  
  public class MementoHandler {
  public static final String ID_FILE = IDtxt;
  private DataConverterMemento objMemento = null;
  public DataConverterMemento getMemento() {
  ObjectInputStream objStream = null;
  FileUtil util = new FileUtil();
  if (utilisFileExists(ID_FILE)) {
  //read the object from the file
  try {
  objStream = new ObjectInputStream(
  new FileInputStream(new File(ID_FILE)));
  objMemento = (DataConverterMemento)
  objStreamreadObject();
  objStreamclose();
  } catch (Exception e) {
  Systemoutprintln(Error Reading Memento);
  Systemexit();
  }
  //delete the old memento
  utildeleteFile(ID_FILE);
  }
  return objMemento;
  }
  public void setMemento(DataConverterMemento memento) {
  ObjectOutputStream objStream = null;
  //write the object to the file
  try {
  objStream = new ObjectOutputStream(
  new FileOutputStream(new File(ID_FILE)));
  objStreamwriteObject(memento);
  objStreamclose();
  } catch (Exception e) {
  Systemoutprintln(Error Writing Memento);
  Systemexit();
  }
  }
  }//end of class
  
  如上面介紹的任何時候數據轉化過程沒有驗證完全部的原數據文件客戶要捕獲DataConverter的狀態到一個Memento中並停止應用程序為了使這個Memento在下次運行的時候有效它必須被保存到持久介質上這就涉及到了對象的序列化如果在下次運行的時候DataConverter要返回到它原來的狀態這個Memento對象必須被重構這又涉及到了對象的反序列化這些細節由MementoHandler類來處理使得所有客戶(DataConverter和Memento對象)免於處理這些細節
  
  這樣也是的改變Memento的存儲方式變得很容易例如Memento需要保存到數據庫中而不是文件中時只要修改MementoHandler就可以了不需要修改任何客戶類的實現
  
  圖顯示了在數據轉化這個例子中不同對象之間的關聯關系
  
 
  Figure : Data Conversion Application?Class Association
  

  Figure shows the application message flow
  
 
  Figure : Application Message Flow
  

  例子(自己找的)
  
  經常使用計算機的人恐怕對系統備份(Memento)不會陌生當你的Windows系統運行正常時對它進行備份當系統運行有問題時就可以調用備份快速的將系統恢復這樣就可以大量節省重新裝系統的痛苦特別是當你缺少某一驅動或在裝系統是出現一些怪問題時猶為痛苦我想有過這種經歷的人應該很了解吧呵呵!
  
  好了下面讓我們看看這個過程該如何實現吧
  
  我們先定義Windows系統(WindowsSystem)類
  
  public class WindowsSystem {
  private String state;
  public Memento createMemento() { //創建備份保存當前狀態
  return new Memento(state);
  }
  public void restoreMemento(Memento memento){ //從備份中恢復系統
  thisstate=mementogetState();
  }
  public String getState(){ //獲得狀態
  return thisstate;
  }
  public void setState(String state){ //設置狀態
  thisstate=state;
  Systemoutprintln(當前系統處於+thisstate);
  }
  }
  
  再定義備份(Memento)類
  
  public class Memento {
  private String state;
  public Memento(String state) { //備份
  thisstate=state;
  }
  public String getState(){ //獲得狀態
  return thisstate;
  }
  public void setState(String state){ //設置狀態
  thisstate=state;
  }
  }
  
  定義用戶(User)類
  
  public class User {
  private Memento memento;
  public Memento retrieveMemento() { //恢復系統
  return mento;
  }
  public void saveMemento(Memento memento){ //保存系統
  mento=memento;
  }
  }
  
  編寫測試類
  
  public class Test {
  public static void main(String args[]) {
  WindowsSystem Winxp = new WindowsSystem(); //Winxp系統
  User user = new User();  //某一用戶
  WinxpsetState(好的狀態);  //Winxp處於好的運行狀態
  usersaveMemento(WinxpcreateMemento()); //用戶對系統進行備份Winxp系統要產生備份文件
  WinxpsetState(壞的狀態);  //Winxp處於不好的運行狀態
  WinxprestoreMemento(userretrieveMemento());  //用戶發恢復命令系統進行恢復
  Systemoutprintln(當前系統處於+WinxpgetState());
  }
  }
  
  說明
  
  A定義Memento對象是一個保存另外一個對象內部狀態拷貝的對象這樣以後就可以將該對象恢復到原先保存的狀態
  
  BMemento模式的用意是在不破壞封裝的條件下將一個對象的狀態捕捉住並外部化存儲起來從而可以在將來合適的時候把這個對象還原到存儲起來的狀態
  
  CMemento模式所涉及的角色有三個備忘錄角色發起人角色和負責人角色
  
  備忘錄角色的作用
  
  ()    將發起人對象的內部狀態存儲起來備忘錄可以根據發起人對象的判斷來決定存儲多少發起人對象的內部狀態
  
  ()    備忘錄可以保護其內容不被發起人對象之外的任何對象所讀取
  
  發起人角色的作用
  
  ()    創建一個含有當前內部狀態的備忘錄對象
  
  ()    使用備忘錄對象存儲其內部狀態
  
  負責人角色的作用
  

  ()    負責保存備忘錄對象
  
  ()    不檢查備忘錄對象的內容
  
  D在本例中備份(Memento)類是備忘錄角色Windows系統(WindowsSystem)類是發起人角色用戶(User)類是負責人角色
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27656.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.