【設計模式-4.7】行為型——備忘錄模式

說明:本文介紹行為型設計模式之一的備忘錄模式

定義

備忘錄模式(Memento Pattern)又叫作快照模式(Snapshot Pattern)或令牌模式(Token Pattern)指在不破壞封裝的前提下,捕獲一個對象的內部狀態,并在對象之外保存這個狀態。這樣以后就可將該對象恢復到原先保存的狀態,屬于行為型設計模式。

(引自《設計模式就該這樣學》P348,發現作者很喜歡使用”XX模式又叫作XX模式“這樣的表述,笑)

編輯器

假設開發一款編輯器軟件,如下,有載入文檔、追加內容、清空內容功能;

(文檔類,Doc)

/*** 文檔類*/
public class Doc {/*** 文檔標題*/private String title;/*** 文檔內容*/private StringBuffer body;public Doc(String title) {this.title = title;this.body = new StringBuffer();}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public StringBuffer getBody() {return body;}public void setBody(StringBuffer body) {this.body = body;}
}

(編輯器,Editor)

/*** 編輯器類*/
public class Editor {private Doc doc;/*** 載入文檔*/public Editor(Doc doc) {System.out.println(">>>載入文檔");this.doc = doc;show();}/*** 追加內容*/public void append(String content){System.out.println(">>>追加內容");doc.getBody().append(content);show();}/*** 清空內容*/public void clear() {System.out.println(">>>清空文檔");doc.getBody().setLength(0);show();}/*** 保存內容*/public void save() {System.out.println(">>>保存中");// todoSystem.out.println(">>>保存成功");}/*** 展示內容*/public void show() {System.out.println(">>>展示內容");System.out.println("文檔標題:" + doc.getTitle());System.out.println("文檔內容:" + doc.getBody());}
}

(客戶端使用,Client)

public class Client {public static void main(String[] args) {// 打開編輯器,開始寫作Editor myDoc = new Editor(new Doc("《論程序員的自我修養》"));// 巴拉巴拉,寫作中myDoc.append("\n第一章:程序員必備知識");myDoc.append("\n第二章:論藝術涵養對程序員編碼的影響");// 看看,嗯,寫得很好myDoc.show();// 保存myDoc.save();// 繼續myDoc.append("\n第三章:論打游戲技術與程序員技術之間的關聯");// 誤操作。。。myDoc.clear();}
}

可見,如果誤操作導致文檔內容被清空,九分甚至十分的糟糕

在這里插入圖片描述

針對以上功能,利用備忘錄模式進行改造,如下:

(首先,創建一個歷史記錄對象,保存文檔內容,History)

/*** 歷史記錄類*/
public class History {private StringBuffer body;public History(StringBuffer body) {this.body = body;}public StringBuffer getBody() {return body;}
}

(其次,文檔對象中,增加保存歷史記錄,恢復歷史記錄的方法)

/*** 文檔類*/
public class Doc {/*** 文檔標題*/private String title;/*** 文檔內容*/private StringBuffer body;public Doc(String title) {this.title = title;this.body = new StringBuffer();}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public StringBuffer getBody() {return body;}public void setBody(StringBuffer body) {this.body = body;}/*** 創建歷史記錄*/public History createHistory() {return new History(new StringBuffer(body));}/*** 恢復歷史記錄*/public void restoreHistory(History history) {body = history.getBody();}
}

注意創建歷史記錄方法里,使用了new StringBuffer(body),而不是直接傳遞body,這里涉及到深拷貝、淺拷貝的問題,大家可以試試看有什么區別。

(最后,改造編輯器類,增加撤銷上一步操作的方法,并在每次修改操作后增加創建快照操作)

import java.util.List;/*** 編輯器類*/
public class Editor {/*** 文檔對象*/private Doc doc;/*** 歷史記錄集合*/private List<History> historyList;/*** 歷史記錄版本號* 初始值為-1*/private int historyVersion = -1;/*** 載入文檔*/public Editor(Doc doc) {System.out.println(">>>載入文檔");this.doc = doc;historyList = new java.util.ArrayList<>();backup();show();}/*** 追加內容*/public void append(String content){System.out.println(">>>追加內容");doc.getBody().append(content);backup();show();}/*** 清空內容*/public void clear() {System.out.println(">>>清空文檔");doc.getBody().setLength(0);backup();show();}/*** 保存內容*/public void save() {System.out.println(">>>保存中");// todoSystem.out.println(">>>保存成功");}/*** 展示內容*/public void show() {System.out.println(">>>展示內容");System.out.println("文檔標題:" + doc.getTitle());System.out.println("文檔內容:" + doc.getBody());}/*** 保存歷史記錄* 或者說創建快照*/private void backup() {historyList.add(doc.createHistory());historyVersion++;}/*** 撤回上一步*/public void undo() {System.out.println(">>>撤銷操作");if (historyVersion == 0) {return;}historyVersion--;History history = historyList.get(historyVersion);doc.restoreHistory(history);show();}
}

(客戶端使用,Client)

public class Client {public static void main(String[] args) {// 打開編輯器,開始寫作Editor myDoc = new Editor(new Doc("《論程序員的自我修養》"));// 巴拉巴拉,寫作中myDoc.append("\n第一章:程序員必備知識");myDoc.append("\n第二章:論藝術涵養對程序員編碼的影響");// 看看,嗯,寫得很好myDoc.show();// 保存myDoc.save();// 繼續myDoc.append("\n第三章:論打游戲技術與程序員技術之間的關聯");// 誤操作。。。myDoc.clear();// 撤回上一步myDoc.undo();}
}

可見撤銷操作成功恢復內容

在這里插入圖片描述

多次撤銷,可實現逐步回退操作

        // 撤回上一步myDoc.undo();myDoc.undo();myDoc.undo();myDoc.undo();

如下,非常nice。如果需要開發往后撤退的功能,也完全可以。

在這里插入圖片描述

使用場景

在《設計模式就該這樣學》(P365)這本書中,提到狀態模式適用于以下場景:

(1)需要保存歷史快照的場景。

(2)希望在對象之外保存狀態,且除了自己,其他類對象無法訪問狀態保存的具體內容。

我覺得如果項目中,需要保存歷史記錄的場景,可以考慮使用備忘錄模式進行改造。

總結

本文介紹了行為型設計模式中的狀態模式,參考《設計模式就該這樣學》、《秒懂設計模式》兩書,編輯器場景是《秒懂設計模式》中的舉例。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/83023.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/83023.shtml
英文地址,請注明出處:http://en.pswp.cn/web/83023.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2025年滲透測試面試題總結-天融信[社招]滲透測試工程師(題目+回答)

安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 天融信[社招]滲透測試工程師 一、Java Spring Boot組件漏洞 1. CVE-2018-1270&#xff08;WebSocket RCE&…

華為OD機考-內存冷熱標記-多條件排序

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的區別while (in.hasNextLine()) { // 注意 while 處理多個 caseint a in.nextInt();int[] arr new int[a];for(int…

PPT轉圖片拼貼工具 v3.0

軟件介紹 這個軟件就是將PPT文件轉換為圖片并且拼接起來。 這個代碼支持導入單個文件也支持導入文件夾 但是目前還沒有解決可視化界面問題。 效果展示 軟件源碼 import os import re import win32com.client from PIL import Image from typing import List, Uniondef con…

NLP學習路線圖(三十):微調策略

在自然語言處理領域,預訓練語言模型(如BERT、GPT、T5)已成為基礎設施。但如何讓這些“通才”模型蛻變為特定任務的“專家”?微調策略正是關鍵所在。本文將深入剖析七種核心微調技術及其演進邏輯。 一、基礎概念:為什么需要微調? 預訓練模型在海量語料上學習了通用語言表…

講述我的plc自學之路 第十三章

我和lora都是那種理想主義者&#xff0c;這是我們的共同之處。但是lora比我要更文藝一些&#xff0c;她讀的書畢竟比我多&#xff0c;上的又是名校。受北大人文氣息的熏陶&#xff0c;她總是對愛情充滿了太多幻想。 “說說你的過往吧&#xff0c;lora。”我給lora倒了一杯啤酒&…

GPU虛擬化

引言 現有如下環境&#xff08;注意相關配置&#xff1a;只有一個k8s節點&#xff0c;且該節點上只有一張GPU卡&#xff09;&#xff1a; // k8s版本 $ kubectl version Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.7&…

【免費數據】2005-2019年我國272個地級市的旅游競爭力多指標數據(33個指標)

旅游業是一個城市的重要產業構成。旅游競爭力是一個城市競爭力的重要構成部分。一個城市的旅游競爭力反映了其在旅游市場競爭中的比較優勢。 今日我們分享的是2005-2019年我國272個地級市的旅游競爭力多指標數據&#xff01;該數據集源自2025年4月發表于《地理學報》的論文成果…

AI智能驅動瀏覽器工具Browser Use詳解

前言 在之前關于 AI 測試相關的幾篇文章中,我們分別介紹了通過 playwright-mcp,以及 midscene.js、magentic ui 等幾個不同的 AI 瀏覽器工具,實現 AI 驅動自動化測試的方法介紹。而其實在這些不斷涌現的新工具出現之前,還有一個更早推出(2024.11),也同樣還在不斷完善的…

新成果:GaN基VCSEL動態物理模型開發

作為高速數據傳輸與光電信號處理的核心器件&#xff0c;垂直腔面發射激光器&#xff08;VCSEL&#xff09;在高速光通信、激光雷達等領域應用廣泛&#xff0c;其動態特性直接關聯器件調制速率及穩定性等關鍵參數。近期&#xff0c;天津賽米卡爾科技有限公司技術團隊開發了GaN基…

嵌入式學習筆記 - freeRTOS xTaskResumeAll( )函數解析

第一部分 移除掛起等待列表中的任務 while( listLIST_IS_EMPTY( &xPendingReadyList ) pdFALSE )//循環尋找直到為空&#xff0c;把全部任務掃描一遍 { pxTCB ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingR…

大數據+智能零售:數字化變革下的“智慧新零售”密碼

大數據+智能零售:數字化變革下的“智慧新零售”密碼 大家好,今天咱們聊聊一個火到不行的話題:大數據在智能零售中的應用。這個領域,不僅是技術的“硬核戰場”,更是商業創新的風口浪尖。誰能玩轉數據,誰就能掌控消費者心智,實現銷售爆發。 咱們不搞枯燥學術,而是用最“…

react 常見的閉包陷阱深入解析

一、引子 先來看一段代碼,你能說出這段代碼的問題在哪嗎? const [count, setCount] = useState(0); useEffect(() => {const timer = setTimeout(() => {setCount(count + 1);}, 1000);return () => clearTimeout(timer); }, []);正確答案: 這段代碼存在閉包陷阱…

零基礎在實踐中學習網絡安全-皮卡丘靶場(第十五期-URL重定向模塊)

本期內容和之前的CSRF&#xff0c;File inclusion有聯系&#xff0c;復習后可以更好了解 介紹 不安全的url跳轉 不安全的url跳轉問題可能發生在一切執行了url地址跳轉的地方。如果后端采用了前端傳進來的(可能是用戶傳參,或者之前預埋在前端頁面的url地址)參數作為了跳轉的目…

Python訓練營---DAY48

DAY 48 隨機函數與廣播機制 知識點回顧&#xff1a; 隨機張量的生成&#xff1a;torch.randn函數卷積和池化的計算公式&#xff08;可以不掌握&#xff0c;會自動計算的&#xff09;pytorch的廣播機制&#xff1a;加法和乘法的廣播機制 ps&#xff1a;numpy運算也有類似的廣播機…

什么是ANSYS ACT? ACT又可以分為哪幾類?

ANSYS作為目前仿真界主流軟件之一&#xff0c;除了給用戶提供其強大的功能之外&#xff0c;還給用戶提供了高度自定義定制的權限。所謂定制&#xff0c;也即用戶可以根據自己仿真需求修改現有功能并展示全新功能的產品內操作。定制的目標是改變現有的用戶體驗&#xff0c;以滿足…

電路圖識圖基礎知識-電動機正反轉控制電路詳解(二十)

1. 轉換開關手動正反轉控制電路 轉換開關&#xff08;QS&#xff09;又稱倒順開關&#xff0c;是一種手動控制裝置&#xff0c;可切換電動機的旋轉方向。它具有三個工作位置&#xff1a;正向、停止和反向。 工作原理&#xff1a; 閉合總電源開關 QS若需正向運轉&#xff0c;將…

Spring Boot微服務架構(十):Docker與K8S部署的區別

Spring Boot微服務在Docker與Kubernetes&#xff08;K8S&#xff09;中的部署存在顯著差異&#xff0c;主要體現在技術定位、管理能力、擴展性及適用場景等方面。以下是兩者的核心區別及實踐對比&#xff1a; 一、技術定位與核心功能 Docker 功能&#xff1a;專注于單節點容器化…

性能剖析:在 ABP 框架中集成 MiniProfiler 實現性能可視化診斷

&#x1f680; 性能剖析&#xff1a;在 ABP 框架中集成 MiniProfiler 實現性能可視化診斷 &#x1f4da; 目錄 &#x1f680; 性能剖析&#xff1a;在 ABP 框架中集成 MiniProfiler 實現性能可視化診斷一、為什么選擇 MiniProfiler&#xff1f; &#x1f9d0;二、集成 MiniProf…

ESP32 在Arduino開發環境中,如果程序運行報錯如何定位程序報錯是哪行代碼

在開發中&#xff0c;我們常常會遇到編譯正常&#xff0c;但是運行過程中程序報錯&#xff0c;然后重啟&#xff0c;在這種情況下&#xff0c;又沒法知道是哪段程序引起的&#xff0c;現在我們就來解決這個問題。 其實ESP32的SDK中已經附帶這些debug的工具了。 首先如果我們程…

Python 包管理器 uv 介紹

Python 包管理器 uv 全面介紹 uv 是由 Astral&#xff08;熱門工具 Ruff 的開發者&#xff09;推出的下一代高性能 Python 包管理器和構建工具&#xff0c;用 Rust 編寫。它旨在解決傳統工具&#xff08;如 pip、virtualenv、pip-tools&#xff09;的性能瓶頸&#xff0c;同時…