設計模式之備忘錄模式(Memento)詳解及代碼示例


一、備忘錄模式的定義與特點

  備忘錄(Memento)模式的定義:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,以便以后當需要時能將該對象恢復到原先保存的狀態。該模式又叫快照模式。

  備忘錄模式能記錄一個對象的內部狀態,當用戶后悔時能撤銷當前操作,使數據恢復到它原先的狀態。

二、備忘錄模式優缺點

  備忘錄模式是一種對象行為型模式,其主要優點如下:

  • 提供了一種可以恢復狀態的機制。當用戶需要時能夠比較方便地將數據恢復到某個歷史的狀態。
  • 實現了內部狀態的封裝。除了創建它的發起人之外,其他對象都不能夠訪問這些狀態信息。
  • 簡化了發起人類。發起人不需要管理和保存其內部狀態的各個備份,所有狀態信息都保存在備忘錄中,並由管理者進行管理,這符合單一職責原則。

  其主要缺點是:

  • 資源消耗大。如果要保存的內部狀態信息過多或者特別頻繁,將會占用比較大的內存資源。

三、備忘錄模式的實現

  備忘錄模式的核心是設計備忘錄類以及用於管理備忘錄的管理者類,備忘錄模式的主要角色如下:

  • 發起人(Originator)角色:記錄當前時刻的內部狀態信息,提供創建備忘錄和恢復備忘錄數據的功能,實現其他業務功能,它可以訪問備忘錄里的所有信息。
  • 備忘錄(Memento)角色:負責存儲發起人的內部狀態,在需要的時候提供這些內部狀態給發起人。
  • 管理者(Caretaker)角色:對備忘錄進行管理,提供保存與獲取備忘錄的功能,但其不能對備忘錄的內容進行訪問與修改。

  備忘錄模式的結構圖如圖所示:

            

  實現代碼如下:

public class MementoPattern
{
    public static void main(String[] args)
    {
        Originator or=new Originator();
        Caretaker cr=new Caretaker();       
        or.setState("S0"); 
        System.out.println("初始狀態:"+or.getState());           
        cr.setMemento(or.createMemento()); //保存狀態      
        or.setState("S1"); 
        System.out.println("新的狀態:"+or.getState());        
        or.restoreMemento(cr.getMemento()); //恢復狀態
        System.out.println("恢復狀態:"+or.getState());
    }
}
//備忘錄
class Memento
{ 
    private String state; 
    public Memento(String state)
    { 
        this.state=state; 
    }     
    public void setState(String state)
    { 
        this.state=state; 
    }
    public String getState()
    { 
        return state; 
    }
}
//發起人
class Originator
{ 
    private String state;     
    public void setState(String state)
    { 
        this.state=state; 
    }
    public String getState()
    { 
        return state; 
    }
    public Memento createMemento()
    { 
        return new Memento(state); 
    } 
    public void restoreMemento(Memento m)
    { 
        this.setState(m.getState()); 
    } 
}
//管理者
class Caretaker
{ 
    private Memento memento;       
    public void setMemento(Memento m)
    { 
        memento=m; 
    }
    public Memento getMemento()
    { 
        return memento; 
    }
}

  測試結果如下:

初始狀態:S0
新的狀態:S1
恢復狀態:S0

四、備忘錄模式的應用場景

  前面學習了備忘錄模式的定義與特點、結構與實現,現在來看該模式的以下應用場景。

  • 需要保存與恢復數據的場景,如玩游戲時的中間結果的存檔功能。
  • 需要提供一個可回滾操作的場景,如 Word、記事本、Photoshop,Eclipse 等軟件在編輯時按 Ctrl+Z 組合鍵,還有數據庫中事務操作。

五、備忘錄模式的擴展

  在前面介紹的備忘錄模式中,有單狀態備份的例子,也有多狀態備份的例子。下面介紹備忘錄模式如何同原型模式混合使用。在備忘錄模式中,通過定義“備忘錄”來備份“發起人”的信息,而原型模式的 clone() 方法具有自備份功能,所以,如果讓發起人實現 Cloneable 接口就有備份自己的功能,這時可以刪除備忘錄類,其結構圖如圖所示:

          

   代碼如下所示:

public class PrototypeMemento
{
    public static void main(String[] args)
    {
        OriginatorPrototype or=new OriginatorPrototype();
        PrototypeCaretaker cr=new PrototypeCaretaker();       
        or.setState("S0"); 
        System.out.println("初始狀態:"+or.getState());           
        cr.setMemento(or.createMemento()); //保存狀態      
        or.setState("S1"); 
        System.out.println("新的狀態:"+or.getState());        
        or.restoreMemento(cr.getMemento()); //恢復狀態
        System.out.println("恢復狀態:"+or.getState());
    }
}
//發起人原型
class OriginatorPrototype  implements Cloneable
{ 
    private String state;     
    public void setState(String state)
    { 
        this.state=state; 
    }
    public String getState()
    { 
        return state; 
    }
    public OriginatorPrototype createMemento()
    { 
        return this.clone(); 
    } 
    public void restoreMemento(OriginatorPrototype opt)
    { 
        this.setState(opt.getState()); 
    }
    public OriginatorPrototype clone()
    {
        try
        {
            return (OriginatorPrototype) super.clone();
        }
        catch(CloneNotSupportedException e)
        {
            e.printStackTrace();
        }
        return null;
    }
}
//原型管理者
class PrototypeCaretaker
{ 
    private OriginatorPrototype opt;       
    public void setMemento(OriginatorPrototype opt)
    { 
        this.opt=opt; 
    }
    public OriginatorPrototype getMemento()
    { 
        return opt; 
    }
}

  運行結果如下:

初始狀態:S0
新的狀態:S1
恢復狀態:S0


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM