Java設(shè)計(jì)模式之備忘錄模式
一、介紹
備忘錄模式(Memento Pattern),屬于行為型設(shè)計(jì)模式。目的是用于保存一個(gè)對(duì)象在某一時(shí)刻的狀態(tài),以便于在將來(lái)某個(gè)時(shí)刻根據(jù)此狀態(tài)恢復(fù)該對(duì)象。
在我們?nèi)粘I钪校瑐渫浀氖褂檬诸l繁。比如,有一個(gè)事情我們完成了35%的進(jìn)度,這時(shí)有另一件更重要的事情需要處理,那么我們需要對(duì)這個(gè)已完成35%的事情進(jìn)行記錄(做了哪些事情,做到什么程度等),當(dāng)那個(gè)更重要的事情完成后,就可以根據(jù)記錄的內(nèi)容(做了哪些事情,做到什么程度等)繼續(xù)處理這件事情,而不至于因?yàn)橥浱幚磉M(jìn)度而導(dǎo)致重復(fù)或疏漏,這個(gè)記錄的過(guò)程就是備忘。
另一個(gè)十分鮮活的例子就是,我們經(jīng)常在對(duì)一些東西進(jìn)行計(jì)數(shù)時(shí)被其他人說(shuō)話而打斷,當(dāng)你回答對(duì)方后自己卻突然忘記數(shù)到哪里了,如果你在說(shuō)話前已經(jīng)數(shù)了相當(dāng)長(zhǎng)一段時(shí)間,那此時(shí)你可能不得不從0重新開(kāi)始計(jì)數(shù)。當(dāng)應(yīng)用備忘錄時(shí),無(wú)論你的計(jì)數(shù)達(dá)到什么程度,在別人和你說(shuō)話時(shí),你先將當(dāng)前計(jì)數(shù)保存記錄下來(lái),在談話完成后,再繼續(xù)計(jì)數(shù)即可,以此避免從0重新開(kāi)始計(jì)數(shù)。
當(dāng)我們系統(tǒng)中存在一個(gè)對(duì)象,
下面是備忘錄模式的概念解釋:
在不破壞封裝性的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)。
二、應(yīng)用舉例
根據(jù)我們?cè)诮榻B中的描述,我們應(yīng)該明白了備忘錄模式的本質(zhì)其實(shí)就是對(duì)象狀態(tài)的保存和讀取。不難發(fā)現(xiàn),備忘錄模式的應(yīng)用到處可見(jiàn)
幾乎所有的軟件
在我們使用的所有軟件無(wú)論是桌面端還是網(wǎng)頁(yè)端,只要有保存功能,就都是備忘錄模式的體現(xiàn)。
比如,我們使用txt文本文檔編輯文本,在編輯的過(guò)程中任意時(shí)刻我們都可以使用ctrl+s對(duì)其保存,當(dāng)再次打開(kāi)該txt文檔時(shí),展示的就是我們最后一次保存時(shí)的文本,這種備忘的介質(zhì)就是硬盤。
再比如,我們?cè)谀骋粋€(gè)網(wǎng)站中對(duì)個(gè)人信息進(jìn)行編輯時(shí),當(dāng)按下保存按鈕時(shí),網(wǎng)頁(yè)會(huì)發(fā)起網(wǎng)絡(luò)請(qǐng)求,將我們編輯的個(gè)人信息發(fā)送到遠(yuǎn)程服務(wù)器,當(dāng)再次打開(kāi)個(gè)人信息頁(yè)面進(jìn)行查看或編輯時(shí),網(wǎng)頁(yè)會(huì)再次向遠(yuǎn)程服務(wù)器發(fā)起請(qǐng)求獲取我們上一次保存?zhèn)€人信息。這種備忘的介質(zhì)就是遠(yuǎn)程數(shù)據(jù)庫(kù)。
java序列化
java的序列化和反序列化過(guò)程也是備忘錄模式的體現(xiàn)。其中,序列化的過(guò)程就相當(dāng)于對(duì)一個(gè)對(duì)象狀態(tài)的保存,反序列化的過(guò)程就相當(dāng)于對(duì)以保存的對(duì)象狀態(tài)進(jìn)行恢復(fù)。
三、基本角色
在標(biāo)準(zhǔn)的備忘錄模式中,包含以下三個(gè)角色:
Memento
保存對(duì)象的內(nèi)部狀態(tài)。即備忘錄本身。而既然是備忘錄,自然有兩個(gè)最基本的方法來(lái)保存和獲取其內(nèi)部保存的狀態(tài):getState()和setState()。
存儲(chǔ)源發(fā)器對(duì)象的狀態(tài)。備忘錄對(duì)象可以包括一個(gè)或多個(gè)狀態(tài)屬性,源發(fā)器可以根據(jù)需要保存和恢復(fù)狀態(tài)。
Originator
創(chuàng)建備忘錄,并保存指定對(duì)象的狀態(tài)。即備忘錄管理者。作為備忘錄的管理者,自然在其內(nèi)部保存著多個(gè)備忘(mementoList)和對(duì)應(yīng)的添加刪除方法(add(memento)和remove(memento))。
需要保存和恢復(fù)狀態(tài)的對(duì)象。它創(chuàng)建一個(gè)備忘錄對(duì)象,用于存儲(chǔ)當(dāng)前對(duì)象的狀態(tài),也可以使用備忘錄對(duì)象恢復(fù)自身的狀態(tài)。
Caretaker
從備忘錄中讀取對(duì)象的狀態(tài)并恢復(fù)對(duì)象。有了備忘錄管理者,我們對(duì)備忘錄的操作應(yīng)轉(zhuǎn)移到管理者上,通過(guò)備忘錄管理者存取備忘錄中的狀態(tài)。
負(fù)責(zé)保存?zhèn)渫泴?duì)象,但不能修改備忘錄對(duì)象的內(nèi)容。它可以存儲(chǔ)多個(gè)備忘錄對(duì)象,并決定何時(shí)將備忘錄恢復(fù)給源發(fā)器。
注意:一般情況下,備忘錄模式無(wú)需抽象組件,但究竟需不需要抽象類根據(jù)實(shí)際情況來(lái)定。
備忘錄的通用UML圖如下所示
四、代碼演示
下面我們通過(guò)代碼對(duì)上面基本角色的分析進(jìn)行演示
備忘錄類Memento
public class Memento { // 對(duì)象某一時(shí)刻的狀態(tài) private String state; // 獲取對(duì)象的狀態(tài) public String getState() { return state; } // 保存對(duì)象的狀態(tài) public void setState(String state) { this.state = state; } }
備忘錄管理員類Originator
public class Originator { // 備忘錄集合 private final List<Memento> mementoList; public Originator() { // 對(duì)備忘錄集合進(jìn)行初始化 this.mementoList = new ArrayList<>(); } // 保存對(duì)象某一狀態(tài)到備忘錄 public void saveState(String state) { Memento memento = new Memento(); memento.setState(state); mementoList.add(memento); } // 獲取某一備忘錄并將其移除 public Memento getMemento(int index) { return mementoList.remove(index); } }
讀取狀態(tài)類Caretaker
public class Caretaker { // 備忘錄管理者 private final Originator originator; // 備忘錄管理者的初始化 public Caretaker(Originator originator) { this.originator = originator; } // 獲取某個(gè)備忘錄中對(duì)象的狀態(tài) public String getState(Integer index) { return originator.getMemento(index).getState(); } }
客戶端測(cè)試代碼
public class MementoDemo { public static void main(String[] args) { // 將對(duì)象的狀態(tài)交給備忘錄管理員通過(guò)備忘錄管理 Originator originator = new Originator(); originator.saveState("第一個(gè)字符串"); originator.saveState("第二個(gè)字符串"); originator.saveState("第三個(gè)字符串"); originator.saveState("第四個(gè)字符串"); originator.saveState("第五個(gè)字符串"); // 讀取備忘錄中對(duì)象的狀態(tài) Caretaker caretaker = new Caretaker(originator); String state5 = caretaker.getState(4); System.out.println(state5); String state4 = caretaker.getState(3); System.out.println(state4); String state3 = caretaker.getState(2); System.out.println(state3); String state2 = caretaker.getState(1); System.out.println(state2); String state1 = caretaker.getState(0); System.out.println(state1); } }
運(yùn)行以上代碼,得到以下輸出
五、總結(jié)
備忘錄模式給我們提供了一種可以恢復(fù)狀態(tài)的機(jī)制,可以使用戶能夠比較方便地回到某個(gè)歷史的狀態(tài),在此同時(shí),備忘錄模式也實(shí)現(xiàn)了信息的封裝,使得用戶不需要關(guān)心狀態(tài)的保存細(xì)節(jié)。
但是,備忘錄模式的可擴(kuò)展性并不是很好,每一種對(duì)象都需要對(duì)應(yīng)一種備忘錄,這將會(huì)導(dǎo)致類的數(shù)量膨脹,對(duì)內(nèi)存無(wú)疑是一種考驗(yàn)。
到此這篇關(guān)于Java設(shè)計(jì)模式之備忘錄模式的文章就介紹到這了,更多相關(guān)Java備忘錄模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Java集合中的基本數(shù)據(jù)結(jié)構(gòu)
總有小伙伴讓我總結(jié)一下Java集合中的基本數(shù)據(jù)結(jié)構(gòu)的相關(guān)知識(shí),今天特地整理了本篇文章,文中有非常詳細(xì)的介紹,需要的朋友可以參考下2021-06-06Java String的intern方法使用場(chǎng)景示例
這篇文章主要介紹了Java String的intern方法使用場(chǎng)景示例,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-11-11SpringBoot短鏈接跳轉(zhuǎn)的代碼實(shí)現(xiàn)
短鏈跳轉(zhuǎn)是一種通過(guò)將長(zhǎng)鏈接轉(zhuǎn)換為短鏈接的方式,以便在互聯(lián)網(wǎng)上進(jìn)行鏈接共享和傳播的技術(shù),短鏈將原始長(zhǎng)鏈接通過(guò)特定算法轉(zhuǎn)換為較短的鏈接,使得它更容易分享、傳播和展示,本文給大家介紹了SpringBoot短鏈接跳轉(zhuǎn)的代碼實(shí)現(xiàn),需要的朋友可以參考下2024-03-03Springboot實(shí)現(xiàn)發(fā)送郵件及注冊(cè)激活步驟
為了方便郵件發(fā)送功能的使用,我們用郵件發(fā)送功能實(shí)現(xiàn)用戶注冊(cè),實(shí)現(xiàn)步驟大概就是進(jìn)行用戶注冊(cè)同時(shí)發(fā)送一封激活郵件,郵件里附帶激活鏈接,關(guān)于Springboot發(fā)送郵件注冊(cè)激活功能的實(shí)現(xiàn)參考下本文吧2021-06-06淺談Java異常的Exception e中的egetMessage()和toString()方法的區(qū)別
下面小編就為大家?guī)?lái)一篇淺談Java異常的Exception e中的egetMessage()和toString()方法的區(qū)別。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07Java語(yǔ)言Consistent Hash算法學(xué)習(xí)筆記(代碼示例)
這篇文章主要介紹了Java語(yǔ)言Consistent Hash算法學(xué)習(xí)筆記(代碼示例),分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02