設計模式之備忘錄模式

2022-09-19 12:02:59

無論是我們在使用word還是記事本,系統都會為我們提供復原的功能,這幾乎是人人都會使用到的功能,而在我們實際開發中,會不會存在一個很複雜的物件,當更改了其中的某一個屬性以後,也提供復原的功能,可以快速恢復到更新前的狀態。提供該功能的模式也正是今天的主題——備忘錄模式。

一、概念理解

書上備忘錄的解釋是,在不破壞封裝的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態,這樣可以在以後將物件恢復到原先儲存的狀態。

其實也就是在一個物件之外再額外的增加一個副本物件,每當我們在物件上更改一些屬性以後就構建一個副本,並把副本存放在一個佇列中,每當回退該物件的時候就從副本中恢復資料。

很顯然需要三個角色:原物件、副本物件、存放副本的佇列。

也即書上的三個角色定義:

Originator(發起人角色):負責建立一個備忘錄,記錄自身需要儲存的狀態,具備狀態回滾功能;即原物件。

Memento(備忘錄角色):用於儲存Originator的內部狀態,且可以防止Originator以外的物件進行存取;即副本物件。

Caretaker(管理員角色):負責儲存、提供管理Memento,無法對Memento的內容進行操作和存取;也即存放副本的佇列。

為了讓概念落地,我們基於備忘錄模式的思想實現視訊草稿箱的功能。

在這個業務場景中,發起人其實就是編輯視訊的編輯器,在這個編輯器中我們能幹啥呢?編輯視訊、從草稿箱匯入、儲存到草稿箱。這不是就是發起人角色的作用嗎!我們稱為編輯草稿。

備忘錄那不就是草稿修改後嗎,我們稱之為完稿。

完稿做好了,要存放到一個列表中用於我們快速修復,那當然就是管理員角色。

基於三個角色我們實現程式碼。

二、案例實現

備忘錄角色(完稿):

就是個基礎物件,用於儲存資料,視訊包含的屬性主要是,標題、封面、視訊地址

/**
 * 備忘錄(完稿)
 * @author tcy
 * @Date 16-09-2022
 */
public class VideoMemento {
    private String title;
    private String videoUrl;
    private String imgs;

    public VideoMemento(String title, String content, String imgs) {
        this.title = title;
        this.videoUrl = content;
        this.imgs = imgs;
    }

    public String getTitle() {
        return title;
    }

    public String getContent() {
        return videoUrl;
    }

    public String getImgs() {
        return imgs;
    }

    @Override
    public String toString() {
        return "ArticleMemento{" +
                "title='" + title + '\'' +
                ", content='" + videoUrl + '\'' +
                ", imgs='" + imgs + '\'' +
                '}';
    }
}

發起人角色(編輯草稿):

在基本物件之上,增加儲存和復原的操作,可以看到和我們定義的完稿長的一樣,只是又增了saveToMemento()方法和undoFromMemento()方法,用於儲存和復原。

/**
 * 發起人 (草稿)
 * @author tcy
 * @Date 16-09-2022
 */
public class Editor {
    private String title;
    private String videoUrl;
    private String imgs;

    public Editor(String title, String videoUrl, String imgs) {
        this.title = title;
        this.videoUrl = videoUrl;
        this.imgs = imgs;
    }

    public String getTitle() {
        return title;
    }

    public String getContent() {
        return videoUrl;
    }

    public String getImgs() {
        return imgs;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setContent(String content) {
        this.videoUrl = content;
    }

    public void setImgs(String imgs) {
        this.imgs = imgs;
    }

    /**
     *  儲存到備忘錄
     * @return
     */
    public VideoMemento saveToMemento(){
        VideoMemento articleMemento = new VideoMemento(this.title,this.videoUrl,this.imgs);
        return articleMemento;
    }

    /**
     * 從備忘錄恢復
     * @param articleMemento
     */
    public void undoFromMemento(VideoMemento articleMemento){
        this.title = articleMemento.getTitle();
        this.videoUrl = articleMemento.getContent();
        this.imgs = articleMemento.getImgs();
    }

    @Override
    public String toString() {
        return "Editor{" +
                "title='" + title + '\'' +
                ", content='" + videoUrl + '\'' +
                ", imgs='" + imgs + '\'' +
                '}';
    }
}

管理員角色(草稿箱):

包括一個棧,用於儲存完稿,利用棧先進後出的特性,實現逐步的復原。

/**
 * 管理者(草稿箱)
 * @author tcy
 * @Date 16-09-2022
 */
public class Caretaker {
    private final Stack<VideoMemento> STACK = new Stack<VideoMemento>();

    public VideoMemento getMemento(){
        VideoMemento videoMemento = STACK.pop();
        return videoMemento;
    }

    public void addMemento(VideoMemento videoMemento){
        STACK.push(videoMemento);
    }
}

讀者可以拉取完整程式碼到本地進行學習,實現程式碼均測試通過後上傳到碼雲

三、總結

備忘錄模式是怎麼回事想必你已經明白了,如果我們在實際開發中有一個物件的功能很複雜,屬性非常的多,這時候備忘錄模式就是一個好的選擇。

備忘錄模式實現也很簡單,在原物件基礎之上再增加一個副本物件,在原物件上額外的增加兩個方法,用於構建一個副本和從副本中取值。再建立一個棧物件,用於儲存、管理副本。

備忘錄模式的優勢突出,會簡化發起人(原物件)的職責,隔離儲存狀態,實現資訊的封裝,使用者端無須關心儲存細節,而且提供了狀態回滾功能。

但是最顯著的缺點就是消耗資源,如果物件改動較大,每一次儲存都會消耗很大的記憶體空間,功能換空間。

備忘錄模式在Jdk和Spring中應用的並不多,在我們實際應用中我們要衡量空間和效率的影響,是否使用備忘錄模式進行合理的取捨。

一、設計模式概述

二、設計模式之工廠方法和抽象工廠

三、設計模式之單例和原型

四、設計模式之建造者模式

五、設計模式之代理模式

六、設計模式之介面卡模式

七、設計模式之橋接模式

八、設計模式之組合模式

九、設計模式之裝飾器模式

十、設計模式之外觀模式

十一、外觀模式之享元模式

十二、設計模式之責任鏈模式

十三、設計模式之命令模式

十四、設計模式之直譯器模式

十五、設計模式之迭代器模式

十六、設計模式之中介者模式