《設計模式之禪》筆記摘錄 - 19.備忘錄模式

備忘錄模式的定義

備忘錄模式(Memento Pattern)提供了一種彌補真實世界缺陷的方法,讓“后悔藥”在程界序的世界中真實可行,其定義如下:Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later. (在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。這樣以后就可將該對象恢復到原先保存的狀態。)

通俗地說,備忘錄模式就是一個對象的備份模式,提供了一種程序數據的備份方法,其通用類圖如圖所示。

我們來看看類圖中的三個角色。

Originator發起人角色。記錄當前時刻的內部狀態,負責定義哪些屬于備份范圍的狀態,負責創建和恢復備忘錄數據。

Memento備忘錄角色。備忘錄角色負責存儲Originator發起人對象的內部狀態,在需要的時候提供發起人需要的內部狀態。

Caretaker備忘錄管理員角色。對備忘錄進行管理、保存和提供備忘錄。

備忘錄模式的應用

由于備忘錄模式有太多的變形和處理方式,每種方式都有它自己的優點和缺點,標準的備忘錄模式很難在項目中遇到,基本上都有一些變換處理方式。因此,我們在使用備忘錄模式時主要了解如何應用以及需要注意哪些事項就成了。

備忘錄模式的使用場景

需要保存和恢復數據的相關狀態場景。

提供一個可回滾(rollback)的操作;比如Word中的CTRL+Z組合鍵,IE瀏覽器中的后退按鈕,文件管理器上的backspace鍵等。

需要監控的副本場景中。例如要監控一個對象的屬性,但是監控又不應該作為系統的主業務來調用,它只是邊緣應用,即使出現監控不準、錯誤報警也影響不大,因此一般的做法是備份一個主線程中的對象,然后由分析程序來分析。

數據庫連接的事務管理就是用的備忘錄模式,想想看,如果你要實現一個JDBC驅動,你怎么來實現事務?還不是用備忘錄模式嘛!

備忘錄模式的注意事項

備忘錄的生命期備忘錄創建出來就要在“最近”的代碼中使用,要主動管理它的生命周期,建立就要使用,不使用就要立刻刪除其引用,等待垃圾回收器對它的回收處理。

備忘錄的性能不要在頻繁建立備份的場景中使用備忘錄模式(比如一個for循環中),原因有二:一是控制不了備忘錄建立的對象數量;二是大對象的建立是要消耗資源的,系統的性能需要考慮。因此,如果出現這樣的代碼,設計師就應該好好想想怎么修改架構了。

備忘錄模式的擴展

clone方式的備忘錄

我們可以通過復制的方式產生一個對象的內部狀態,這是一個很好的辦法,發起人角色只要實現Cloneable就成,比較簡單,我們來看類圖:

現在我們來考慮一下原型模式深拷貝和淺見的問題,在復雜的場景下它會讓你的程序邏輯異常混亂,出現錯誤也很難跟蹤。因此Clone方式的備忘錄模式適用于較簡單的場景。

注意 使用Clone方式的備忘錄模式,可以使用在比較簡單的場景或者比較單一的場景中,盡量不要與其他的對象產生嚴重的耦合關系。

多狀態的備忘錄模式

實際的開發中一個對象不可能只有一個狀態,一個JavaBean有多個屬性非常常見,這都是它的狀態,如果照搬我們以上講解的備忘錄模式,是不是就要寫一堆的狀態備份、還原語句?這不是一個好辦法,這種類似的非智力勞動越多,犯錯誤的幾率越大,那我們有什么辦法來處理多個狀態的備份問題呢?

下面我們來講解一個對象全狀態備份方案,它有多種處理方式,比如使用Clone的方式就可以解決,使用數據技術也可以解決(DTO回寫到臨時表中)等,我們要講的方案就對備忘錄模式繼續擴展一下,實現一個JavaBean對象的所有狀態的備份和還原,如圖所示。

加了一個BeanUtils類,其中backupProp是把發起人的所有屬性值轉換到HashMap中,方便備忘錄角色存儲;restoreProp方法則是把HashMap中的值返回到發起人角色中。可能各位要說了,為什么要使用HashMap,直接使用Originator對象的拷貝不是一個很好的方法嗎?可以這樣做,你就破壞了發起人的通用性,你在做恢復動作的時候需要對該對象進行多次賦值操作,也容易產生錯誤。

注意 如果要設計一個在運行期決定備份狀態的框架,則建議采用AOP框架來實現,避免采用動態代理無謂地增加程序邏輯復雜性。

多備份的備忘錄

檢查點(Check Point),也就是你在備份的時候做的戳記,系統級的備份一般是時間戳,那我們程序的檢查點該怎么設計呢?一般是一個有意義的字符串。

注章 內存溢出問題,該備份一旦產生就裝入內存,沒有任何銷毀的意向,這是非常危險的。因此,在系統設計時要限定備忘錄的創建,建議增加Map的上限,否則系統很容易產生存溢出情況。

封裝得更好一點

建立一個空接口IMemento,什么方法屬性都沒有的接口,然后在發起人Originator類中建立一個內置類(也叫做類中類)Memento實現IMemento接口,同時也實現自己的業務邏輯

在這里我們使用了一個新的設計方法:雙接口設計,我們的一個類可以實現多個接口,在系統設計時,如果考慮對象的安全問題,則可以提供兩個接口,一個是業務的正常接口,實現必要的業務邏輯,叫做寬接口;另外一個接口是一個空接口,什么方法都沒有,其目的是提供給子系統外的模塊訪問,比如容器對象,這個叫做窄接口,由于窄接口中沒有提供任何操縱數據的方法,因此相對來說比較安全。

最佳實踐

備忘錄模式是我們設計上“月光寶盒,可以讓我們回到需要的年代;是程序數據的“后悔藥”,吃了它就可以返回上一個狀態;是設計人員的定心丸,確保即使在最壞的情況下也能獲得最近的對象狀態。如果大家看懂了的話,請各位在設計的時候就不要使用數據庫的臨時表作為緩存備份數據了,雖然是一個簡單的辦法,但是它加大了數據庫操作的頻繁度,把壓力下故到數據庫了,最好的解決辦法就是使用備忘錄模式。

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

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

相關文章

22、Jenkins容器化部署Java應用

22、Jenkins容器化部署Java應用 1、準備Dockerfile 將Dockerfile文件放入項目目錄下 FROM registry.cn-hangzhou.aliyuncs.com/xx_blog/openjdk:21-jdk LABEL maintainer"xxqq.com" #復制打好的jar包 COPY target/*.jar /app.jar RUN apk add -U tzdata; \ ln -sf /…

基于單片機智能水龍頭/智能洗漱臺設計

傳送門 👉👉👉👉其他作品題目速選一覽表 👉👉👉👉其他作品題目功能速覽 概述 該設計采用單片機作為核心控制器,結合紅外傳感器、水流傳感器和電磁閥等模塊&#xf…

GD32入門到實戰30--產品配置參數存儲方案 (EEPROM)

我們之前已經實現eeprom的驅動了,我們在應用層實現產品配置參數存儲方案我們要實現:原本設定的modebus從機(單片機)地址是01,存儲在eeprom里,按下按鍵后修改地址為03,重新上電modebus從機&#…

find_code 插件 react_vite

find_code 插件 react_vite const fs require("fs"); const path require("path"); const parser require("babel/parser"); const traverse require("babel/traverse").default; const generate require("babel/generator&…

手機秒變全棧IDE:Claude Code UI的深度體驗

還在為只能在命令行中使用Claude Code而苦惱嗎?想在移動設備上繼續你的AI編程對話嗎?Claude Code UI的出現徹底改變了這一切。這個開源項目為Anthropic官方的Claude Code CLI工具提供了現代化的Web界面,讓你能夠在任何設備、任何地方與AI編程…

F5發布后量子API安全解決方案,以AI驅動全面防護應對量子計算威脅

量子計算的飛速演進,正對傳統加密體系構成日益嚴峻的安全威脅。Gartner預測顯示,到2029年,量子計算機有望攻破目前普遍采用的公鑰加密算法,這一風險正倒逼全球企業加速密碼體系的更迭與升級。面對這一挑戰,F5公司——應…

深度剖析 DC - DC 轉換器在新能源汽車中的關鍵應用

在新能源汽車的發展進程中,DC - DC 轉換器扮演著至關重要的角色。以下將詳細介紹其在新能源汽車上的應用,包括作用、電路組成以及工作原理等方面。DC - DC 轉換器的作用簡單來說,新能源汽車上的 DC - DC 轉換器是一個 “降壓型電壓變換器”。…

【標準項目】在線五子棋對決(下)

在線五子棋對決一. 項目介紹及鏈接二. 項目結構設計項目模塊劃分業務處理模塊的子模塊劃分項目流程圖玩家流程圖服務器流程圖三. 數據管理模塊數據庫設計創建 user_table 類四. 在線用戶管理模塊五. 游戲房間管理模塊游戲房間類實現游戲房間管理類實現六. Session 管理模塊Sess…

重構導航之核:高德地圖的深度學習架構解析 導論:從數字化世界到可計算世界

導論:從數字化世界到可計算世界 數字地圖的演進,本質上是一場關于“世界可計算性”的持續探索。第一代地圖的核心任務是數字化轉錄(Digital Transcription),它成功地將物理世界的靜態元素——道路、建筑、興趣點&#…

邏輯回歸(sigmoid函數、混淆矩陣、精確率召回率F1)

目錄 一、概述 1、邏輯回歸 2、激活函數 sigmoid函數 3、最大似然估計 二、邏輯回歸 1、原理 2、損失函數 3、代碼 三、混淆矩陣 1、定義 2、舉例 3、代碼 四、分類評估方法 1、精確率(Precision) 2、召回率(Recall) 3、F1&#…

Redis底層實現原理之五大基礎結構

文章目錄1. 基礎結構和編碼類型2. 編碼類型和數據結構實現2.1 字符串(String)2.2 壓縮列表(listpack)2.3 哈希表(hashtable)2.4 快速列表(quicklist)2.5 整數集合(intset…

火山引擎數據智能體DataAgent總結分享

數據的冰山:看得見的資產與看不見的鴻溝 這張圖片用“冰山”類比的方式展示了數據資產管理中的可見與不可見問題,并突出了數據利用的核心挑戰與潛在陷阱。 1. 冰山之上的“看得見的資產” 內容:數據庫、報表、指標等結構化、顯性的數據資源。 核心挑戰: 需要從“采集存儲”…

100種高級數據結構 (速查表)

一、 基礎結構的擴展與組合 (Advanced Linear Structures) 這些結構在數組、鏈表、隊列、棧等基礎結構上增加了特定功能或約束。雙端隊列 (Deque - Double-Ended Queue) 介紹:允許在隊列的前后兩端都進行插入和刪除操作的線性結構。應用場景:工作竊取算法…

一個開源的企業官網簡介

簡介一個完美的企業官網系統,支持手機端和電腦端展示企業風采,還可以展示企業產品/企業新聞資訊等等.普通用戶PC端展示普通用戶手機端展示管理后臺

TCP實現線程池競爭任務

服務端&#xff1a;#include<stdio.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<netinet/ip.h> #include<strings.h> #include<unistd.h> #include<ctype.h> #include<arpa/inet.h&…

Redis C++ 實現筆記(F篇)

Implementing Redis in C : F Redis C 實現筆記&#xff08;F篇&#xff09; 前言 本章代碼及思路均來自Build Your Own Redis with C/C 本文章只闡述我的理解想法&#xff0c;以及需要注意的地方。 本文章為續<<Implementing Redis in C : E>>所以本文章不再…

finally 與 return的執行順序

一、第一次試驗public static void main(String[] args) throws InterruptedException {System.out.println(aaa(null));}private static StringBuilder aaa(Integer i) throws InterruptedException {StringBuilder sb new StringBuilder();try {i.toString();return sb;} ca…

Git安裝教程

簡介 Git 是目前全球最流行的分布式版本控制系統&#xff08;Distributed Version Control System, DVCS&#xff09;&#xff0c;核心作用是追蹤文件修改歷史、支持多人協同開發&#xff0c;并能高效管理代碼&#xff08;或任何文本類文件&#xff09;的版本迭代。它由 Linux…

Linux安裝RTL8821CE無線網卡驅動

1. 查看網卡芯片$ lspci | grep Net 01:00.0 Network controller: Realtek Semiconductor Co., Ltd. RTL8821CE 802.11ac PCIe Wireless Network Adapter2. 預備配套sudo apt install -y dkms git3. 下載驅動并安裝git clone https://github.com/tomaspinho/rtl8821ce.git cd r…

vue3存儲/獲取本地或會話存儲,封裝存儲工具,結合pina使用存儲

目錄 一、基本用法&#xff08;原生 API&#xff09; 1. 存儲數據 2. 獲取數據 3. 刪除數據 二、Vue3 中封裝成工具函數&#xff08;推薦&#xff09; 三、以上工具函數在 Vue3 組件中使用 1. 在選項式 API 中使用 2. 在組合式 API&#xff08;setup 語法糖&#xff09;…