設計模式是什麼鬼(備忘錄)

来源:https://www.cnblogs.com/javazhiyin/archive/2018/10/29/9869002.html
-Advertisement-
Play Games

備忘錄,備份曾經發生過的歷史記錄,以防忘記,之後便可以輕鬆回溯過往。想必我們曾經都乾過很多蠢事導致糟糕的結果,當後悔莫及的時候已經是覆水難收了,只可惜這世界上沒有後悔藥,事後我們能做的只能去彌補過失,總結經驗。除非穿越時空,時光倒流,利用愛因斯坦狹義相對論,超越光速回到過去,破鏡重圓。 然而世界是殘 ...


備忘錄,備份曾經發生過的歷史記錄,以防忘記,之後便可以輕鬆回溯過往。想必我們曾經都乾過很多蠢事導致糟糕的結果,當後悔莫及的時候已經是覆水難收了,只可惜這世界上沒有後悔藥,事後我們能做的只能去彌補過失,總結經驗。除非穿越時空,時光倒流,利用愛因斯坦狹義相對論,超越光速回到過去,破鏡重圓。

設計模式是什麼鬼(備忘錄)

然而世界是殘酷的,人類至今最快的載人交通工具連達到光速的萬分之一都顯得遙不可及,更別說超越了。光速,宇宙間永遠無法打破的時空屏障,它像是上帝定義的常量C,將時間牢牢地套死在坐標軸上,自創世宇宙大爆炸開始就讓它不斷流逝,如同播放一部不可回退的電影一樣,暮去朝來,誰也無法打破。

設計模式是什麼鬼(備忘錄)

但在電腦世界里,人類便是神一般的存在,各種回滾,倒退,載入歷史顯得稀鬆平常,例如資料庫恢復、游戲存檔載入、操作系統快照恢復、打開備份文檔、手機恢復出廠設置……為了保證極簡風格,我們這裡以文檔操作來舉例說明這個設計模式。

假設某位作者要寫一部科幻小說,當他打開編輯器軟體以及創建文檔開始創作的時候,我們來思考下這個場景需要哪些類。很簡單,首先我們得有一個文檔類Doc。

  

public class Doc {
   private String title;//文章標題
  private String body;//文章內容

   public Doc(String title){//新建文檔先命名
       this.title = title;
       this.body = "";
   }

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

    public String getTitle() {
        return title;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }
}

  

沒什麼好說的,一個簡單的Java Bean,包括標題與內容。有了文檔那一定要有編輯器去修改它了,看代碼。

  

public class Editor {//編輯器
    private Doc doc;//文檔引用

    public Editor(Doc doc) {
        System.out.println("<<<打開文檔" + doc.getTitle());
        this.doc = doc;
        show();
    }

    public void append(String txt) {
        System.out.println("<<<插入操作");
        doc.setBody(doc.getBody() + txt);
        show();
    }

    public void save(){
        System.out.println("<<<存檔操作");
    }

    public void delete(){
        System.out.println("<<<刪除操作");
        doc.setBody("");
        show();
    }

    private void show(){//顯示當前文本內容
        System.out.println(doc.getBody());
        System.out.println("文章結束>>>n");
    }
}

  

當編輯器打開一個文檔後會持有其引用,這裡我們寫在編輯器構造方法里。編輯器主要的功能當然是對文檔進行更改了,依然保持簡單的操作模擬,我們只加入append插入功能、delete清空功能,以及save存檔方法和最後的show方法用於顯示文檔內容。一切就緒,接下來看看我們的作者怎樣寫出一部驚世駭俗的科幻小說《AI的覺醒》。

  

public class Author {
    public static void main(String[] args) {
        Editor editor = new Editor(new Doc("《AI的覺醒》"));
        /*
        <<<打開文檔《AI的覺醒》

        文章結束>>>
        */
        editor.append("第一章 混沌初開");
        /*
        <<<插入操作
        第一章 混沌初開
        文章結束>>>
        */
        editor.append("n  正文2000字……");
        /*
        <<<插入操作
        第一章 混沌初開
          正文2000字……
        文章結束>>>
        */
        editor.append("n第二章 荒漠之花n  正文3000字……");
        /*
        <<<插入操作
        第一章 混沌初開
          正文2000字……
        第二章 荒漠之花
          正文3000字……
        文章結束>>>
        */
        editor.delete();
        /*
        <<<刪除操作

        文章結束>>> 
        */
    }
}

  

鬼才作者開始了創作,一切進行地非常順利,一氣呵成寫完了二章內容(第22行操作),於是他離開電腦去倒了杯咖啡,噩耗在此間發生了,他的熊孩子不知怎麼就按下了Ctr+A,Delete觸發了第31行的操作,導致全文丟失,從記憶體里被清空,而且離開前作者疏忽大意也沒有進行存檔操作,這下徹底完了,5000字的心血付諸東流。

設計模式是什麼鬼(備忘錄)

此場景該如何是好?大家都想到了Ctr+z的操作吧?它可以瞬間撤銷上一步操作並回退到前一個版本,不但讓我們有吃後悔藥的機會,而且還不需要頻繁的去存檔備份。那麼這個機制是怎樣實現的呢?既然可以回溯歷史,那一定得有一個歷史備忘類來記錄每步操作後的文本狀態記錄了,它同樣是一個簡單的Java Bean。

  

public class History {
    private String body;//用於備忘文章內容

    public History(String body){
        this.body = body;
    }

    public String getBody() {
        return body;
    }
}

  

有了這個類,我們便可以記錄文檔的內容快照了,在初始化時把文檔內容傳進來。那誰來生成這些歷史記錄呢?我們可以放在文檔類里,讓文檔類具備創建與恢復歷史記錄的功能,我們對Doc文檔類做如下修改。

  

 public class Doc {
    private String title;//文章名字
    private String body;//文章內容
 
    public Doc(String title){//新建文檔先命名
        this.title = title;
        this.body = "";
    }

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

    public String getTitle() {
        return title;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public History createHistory() {
        return new History(body);//創建歷史記錄
    }

    public void restoreHistory(History history){
        this.body = history.getBody();//恢復歷史記錄
    }
}

  

可以看到自第26行開始我們加入了這兩個功能,只要簡單的調用,便可以生成當下的歷史記錄,以及來去自如的恢復內容到任一歷史時刻。接下來得有對歷史記錄的邏輯控制,也就是我們期待已久的撤銷功能了,繼續對編輯器類做如下修改

  

 public class Editor {
    private Doc doc;
    private List<History> historyRecords;// 歷史記錄列表
    private int historyPosition = -1;// 歷史記錄當前位置

    public Editor(Doc doc) {
        System.out.println("<<<打開文檔" + doc.getTitle());
        this.doc = doc; // 註入文檔
        historyRecords = new ArrayList<>();// 初始化歷史記錄
        backup();// 保存一份歷史記錄
        show();//顯示內容
    }

    public void append(String txt) {
        System.out.println("<<<插入操作");
        doc.setBody(doc.getBody() + txt);
        backup();//操作完成後保存歷史記錄
        show();
    }

    public void save(){
        System.out.println("<<<存檔操作");
    }

    public void delete(){
        System.out.println("<<<刪除操作");
        doc.setBody("");
        backup();//操作完成後保存歷史記錄
        show();
    }

    private void backup() {
        historyRecords.add(doc.createHistory());
        historyPosition++;
    }

    private void show() {// 顯示當前文本內容
        System.out.println(doc.getBody());
        System.out.println("文章結束>>>n");
    }

    public void undo() {// 撤銷操作:如按下Ctr+Z,回到過去。
        System.out.println(">>>撤銷操作");
        if (historyPosition == 0) {
            return;//到頭了,不能再撤銷了。
        }
        historyPosition--;//歷史記錄位置回滾一筆
        History history = historyRecords.get(historyPosition);
        doc.restoreHistory(history);//取出歷史記錄並恢復至文檔
        show();
    }

    // public void redo(); 省略實現代碼
}

  

在第3行我們加入了一個歷史記錄列表,它就像是時間軸一樣按順序地按index記錄每個時間點的歷史事件,從某種意義上看它更像是一本歷史書。接下來加入的第32行backup方法會從文檔中拿出快照並插入歷史書,並於每個暴露給客戶端作者的操作方法內被調用,做好歷史的傳承。最後我們加入第42行的撤銷操作,讓時間點回溯一個單位並恢復此處的快照至文檔。當編輯器擁有了撤銷功能後,我們的鬼才作者將高枕無憂的去倒咖啡了。

  

 public class Author {
    public static void main(String[] args) {
        Editor editor = new Editor(new Doc("《AI的覺醒》"));
        /*
        <<<打開文檔《AI的覺醒》

        文章結束>>>
        */
        editor.append("第一章 混沌初開");
        /*
        <<<插入操作
        第一章 混沌初開
        文章結束>>>
        */
        editor.append("n  正文2000字……");
        /*
        <<<插入操作
        第一章 混沌初開
          正文2000字……
        文章結束>>>
        */
        editor.append("n第二章 荒漠之花n  正文3000字……");
        /*
        <<<插入操作
        第一章 混沌初開
          正文2000字……
        第二章 荒漠之花
          正文3000字……
        文章結束>>>
        */
        editor.delete();
        /*
        <<<刪除操作

        文章結束>>> 
        */

        //吃下後悔藥,我的世界又完整了。
        editor.undo();
        /*
        >>>撤銷操作
        第一章 混沌初開
          正文2000字……
        第二章 荒漠之花
          正文3000字……
        文章結束>>>
        */
    }
}

  

可以看到,熊孩子做了delete操作後,作者輕鬆淡定地按下了Ctr+z,一切恢復如初,世界依舊美好,輓回那逝去的青蔥歲月。當然,代碼中我們略去了一些功能,比如讀者還可以加入重做redo操作,彈指之間,讓歷史在時間軸上來去自如,我的電腦我做主,時空穿梭,逆天之做。

設計模式是什麼鬼(備忘錄)

誠然,任何模式都有其優缺點,備忘錄雖然看起來完美,但如果歷史狀態內容過大,會導致記憶體消耗嚴重,別忘了那邊歷史書的list是在記憶體中的哦,所以我們一定要依場景靈活運用,切不可生搬硬套。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • elementUI vue tree input 懶載入 輸入下拉樹型示例 ...
  • 就是這麼簡單的一句話,設置背景圖,並讓它100%的適應導航欄寬高,並設置不重覆,大小100%就OK了 轉載來源:https://blog.csdn.net/chenqk_123/article/details/44402355 ...
  • 在您的照片庫中加入成千上萬張高品質的照片,涵蓋各種主題和風格!下麵列出的網站提供可用於任何項目的圖像,沒有限制。您不必擔心因為一張小圖片的版權而導致麻煩。通過這些網站可以改善你的設計項目,這些是網上提供免費的高質量圖片最好的網站。作為設計師,都知道如何藉助免費素材來解放工作。他們經常會花好幾個小時去... ...
  • 一,效果圖。 二,代碼。 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>html 列表</title> </head> <body> <!--創建文本欄位text field--> <form action=""> first ...
  • 我們在做css的時候為了提高網站的效率減少伺服器請求,我們可以通過css來實現一些簡單的圖片特效,比如說三角形,這篇文章講解的是通過邊框實現不同的效果。 首先看一下不同邊框樣式的效果: 代碼部分: 1 <style type="text/css"> 2 .style-border b { 3 bor ...
  • jQuery CDN PS:jQuery 2.0 以上版本不再支持IE 6/7/8 REF: "https://www.sojson.com/jquery/down.html" 經多次測試,建議使用百度的CDN引用地址,官網的地址有可能造成部分地區打開略有延遲 Version Baidu Examp ...
  • Vue 組件之間傳值 一、父組件向子組件傳遞數據 在 Vue 中,可以使用 props 向子組件傳遞數據。 子組件部分: 這是 header.vue 的 HTML 部分,logo 是在 data 中定義的變數。 如果需要從父組件獲取 logo 的值,就需要使用 props: ['logo'] 在 p ...
  • ```php ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...