欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java設(shè)計(jì)模式之java備忘錄模式詳解

 更新時(shí)間:2021年09月15日 10:53:13   作者:大忽悠愛(ài)忽悠  
這篇文章主要介紹了JAVA設(shè)計(jì)模式之備忘錄模式,簡(jiǎn)單說(shuō)明了備忘錄模式的概念、原理并結(jié)合實(shí)例形式分析了java備忘錄模式的具體定義及使用方法,需要的朋友可以參考下

引言

備忘錄模式經(jīng)??梢杂龅?,譬如下面這些場(chǎng)景:

  • 瀏覽器回退:瀏覽器一般有瀏覽記錄,當(dāng)我們?cè)谝粋€(gè)網(wǎng)頁(yè)上點(diǎn)擊幾次鏈接之后,可在左上角點(diǎn)擊左箭頭回退到上一次的頁(yè)面,然后也可以點(diǎn)擊右箭頭重新回到當(dāng)前頁(yè)面
  • 數(shù)據(jù)庫(kù)備份與還原:一般的數(shù)據(jù)庫(kù)都支持備份與還原操作,備份即將當(dāng)前已有的數(shù)據(jù)或者記錄保留,還原即將已經(jīng)保留的數(shù)據(jù)恢復(fù)到對(duì)應(yīng)的表中
  • 編輯器撤銷(xiāo)與重做:在編輯器上編輯文字,寫(xiě)錯(cuò)時(shí)可以按快捷鍵 Ctrl + z 撤銷(xiāo),撤銷(xiāo)后可以按 Ctrl + y 重做
  • 虛擬機(jī)生成快照與恢復(fù):虛擬機(jī)可以生成一個(gè)快照,當(dāng)虛擬機(jī)發(fā)生錯(cuò)誤時(shí)可以恢復(fù)到快照的樣子
  • Git版本管理:Git是最常見(jiàn)的版本管理軟件,每提交一個(gè)新版本,實(shí)際上Git就會(huì)把它們自動(dòng)串成一條時(shí)間線(xiàn),每個(gè)版本都有一個(gè)版本號(hào),使用 git reset --hard 版本號(hào) 即可回到指定的版本,讓代碼時(shí)空穿梭回到過(guò)去某個(gè)歷史時(shí)刻
  • 棋牌游戲悔棋:在棋牌游戲中,有時(shí)下快了可以悔棋,回退到上一步重新下

備忘錄模式(Memento Pattern)

在不破壞封裝的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài),這樣可以在以后將對(duì)象恢復(fù)到原先保存的狀態(tài)。它是一種對(duì)象行為型模式,其別名為T(mén)oken。

角色

  • Originator(原發(fā)器):它是一個(gè)普通類(lèi),可以創(chuàng)建一個(gè)備忘錄,并存儲(chǔ)它的當(dāng)前內(nèi)部狀態(tài),也可以使用備忘錄來(lái)恢復(fù)其內(nèi)部狀態(tài),一般將需要保存內(nèi)部狀態(tài)的類(lèi)設(shè)計(jì)為原發(fā)器,需要被數(shù)據(jù)備份的對(duì)象
  • Memento(備忘錄):存儲(chǔ)原發(fā)器的內(nèi)部狀態(tài),根據(jù)原發(fā)器來(lái)決定保存哪些內(nèi)部狀態(tài)。備忘錄的設(shè)計(jì)一般可以參考原發(fā)器的設(shè)計(jì),根據(jù)實(shí)際需要確定備忘錄類(lèi)中的屬性。需要注意的是,除了原發(fā)器本身與負(fù)責(zé)人類(lèi)之外,備忘錄對(duì)象不能直接供其他類(lèi)使用,原發(fā)器的設(shè)計(jì)在不同的編程語(yǔ)言中實(shí)現(xiàn)機(jī)制會(huì)有所不同。用來(lái)保存?zhèn)浞輸?shù)據(jù)的對(duì)象
  • Caretaker(負(fù)責(zé)人):負(fù)責(zé)人又稱(chēng)為管理者,它負(fù)責(zé)保存?zhèn)渫?,但是不能?duì)備忘錄的內(nèi)容進(jìn)行操作或檢查。在負(fù)責(zé)人類(lèi)中可以存儲(chǔ)一個(gè)或多個(gè)備忘錄對(duì)象,它只負(fù)責(zé)存儲(chǔ)對(duì)象,而不能修改對(duì)象,也無(wú)須知道對(duì)象的實(shí)現(xiàn)細(xì)節(jié)。備份的數(shù)據(jù)會(huì)有多份,因此需要有一個(gè)類(lèi)來(lái)管理這些備份

備忘錄模式的核心是備忘錄類(lèi)以及用于管理備忘錄的負(fù)責(zé)人類(lèi)的設(shè)計(jì)。

說(shuō)明:如果希望保存多個(gè)originator對(duì)象的不同時(shí)間的狀態(tài),也可以,只需要 HashMap <String, 集合>

為什么會(huì)出現(xiàn)守護(hù)者對(duì)象(負(fù)責(zé)人)?

舉個(gè)例子說(shuō)明,下棋軟件要提供“悔棋”功能,用戶(hù)走錯(cuò)棋或操作失誤后可恢復(fù)到前一個(gè)步驟?;谄蹇赡芑氐缴弦徊?,也有可能回到上上次的狀態(tài)…因此需要記錄多次的狀態(tài)

在這里插入圖片描述

在這里插入圖片描述

在設(shè)計(jì)備忘錄類(lèi)時(shí)需要考慮其封裝性,除了Originator類(lèi),不允許其他類(lèi)來(lái)調(diào)用備忘錄類(lèi)Memento的構(gòu)造函數(shù)與相關(guān)方法,如果不考慮封裝性,允許其他類(lèi)調(diào)用setState()等方法,將導(dǎo)致在備忘錄中保存的歷史狀態(tài)發(fā)生改變,通過(guò)撤銷(xiāo)操作所恢復(fù)的狀態(tài)就不再是真實(shí)的歷史狀態(tài),備忘錄模式也就失去了本身的意義。

備忘錄模式實(shí)現(xiàn)框架

originator : 對(duì)象(需要保存狀態(tài)的對(duì)象)

public class Originator {
    private String state;//狀態(tài)
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
    //編寫(xiě)一個(gè)方法,可以保存一個(gè)狀態(tài)對(duì)象Memento
    public Memento saveStateMemento(){
        return new Memento(state);
    }
    public void getStateFromMemento (Memento memento){
        state = memento.getState();
    }
}

Memento : 備忘錄對(duì)象,負(fù)責(zé)保存好記錄,即Originator內(nèi)部狀態(tài)

public class Memento {
    private String state;
    public Memento(String state) {
        this.state = state;
    }
    public String getState() {
        return state;
    }
}

Caretaker: 守護(hù)者對(duì)象,負(fù)責(zé)保存多個(gè)備忘錄對(duì)象, 使用集合管理,提高效率

public class Caretaker {
    //List集合中會(huì)有很多備忘錄對(duì)象
    private List<Memento> mementoList = new ArrayList<>();
    public void add(Memento memento) {
        mementoList.add(memento);
    }
    //獲取到第index個(gè)Origintor的備忘錄對(duì)象
    public Memento get(int index){
        return mementoList.get(index);
    }
}

下棋案例

棋子類(lèi) Chessman,原發(fā)器角色

//原發(fā)器,需要保存對(duì)象的狀態(tài)
@Data
@AllArgsConstructor
public class Chessman
{
    private String label;//當(dāng)前棋子的名字: 車(chē),炮,馬
    private Integer x,y;//當(dāng)前棋子的坐標(biāo)
    //保存當(dāng)前對(duì)象的狀態(tài)--備份數(shù)據(jù)
    public ChessmanMemento save()
    {
        return new ChessmanMemento(label,x,y);
    }
    //恢復(fù)當(dāng)前對(duì)象的狀態(tài)
    public void restore(ChessmanMemento chessmanMemento)
    {
        this.label=chessmanMemento.getLabel();
        this.x=chessmanMemento.getX();
        this.y=chessmanMemento.getY();
    }
    //展示當(dāng)前對(duì)象的狀態(tài)
    public void show()
    {
        System.out.println(
                String.format("棋子: %s ,位置: [%d,%d]",label,x,y)
        );
    }
}

備忘錄角色 ChessmanMemento

//負(fù)責(zé)備份的棋子狀態(tài)
@Data
@AllArgsConstructor
public class ChessmanMemento
{
    private String label;
    private Integer x,y;
}

負(fù)責(zé)人角色 MementoCaretaker

//負(fù)責(zé)保存多個(gè)備份對(duì)象
public class MementoCaretaker
{
   //記錄當(dāng)前所處的備份狀態(tài)
   Integer index=-1;//一開(kāi)始沒(méi)有備份數(shù)據(jù)
  //通過(guò)一個(gè)List集合保存多個(gè)備份對(duì)象
    List<ChessmanMemento> chessmanMementoLinkedList= Lists.newLinkedList();
  //悔棋操作--恢復(fù)到上一個(gè)備忘錄狀態(tài)
    public  ChessmanMemento getMemento()
    {
        if(index<=0)
        {
            throw new IndexOutOfBoundsException("已經(jīng)無(wú)棋可悔了");
        }
        this.index--;//當(dāng)前所處的備份狀態(tài)減去一
        //將當(dāng)前狀態(tài)之后的狀態(tài)全部清空
        //保留前index個(gè)元素,并將流收集到List中
        chessmanMementoLinkedList = chessmanMementoLinkedList.stream()
                .limit(this.index+1).collect(Collectors.toList());
        return chessmanMementoLinkedList.get(index);
    }
    //下棋---增加新的備份對(duì)象
    public void addMemento(ChessmanMemento chessmanMemento)
    {
        index++;
        chessmanMementoLinkedList.add(chessmanMemento);
    }
}

棋子客戶(hù)端,維護(hù)了一個(gè) MementoCaretaker 對(duì)象

//客戶(hù)端
public class Client
{
  //維護(hù)一個(gè)守護(hù)者對(duì)象
  MementoCaretaker mementoCaretaker=new MementoCaretaker();
 //下棋
    public void play(Chessman chessman)
    {
        //通過(guò)調(diào)用備份返回,返回一個(gè)備份對(duì)象,添加進(jìn)備份集合中去
        mementoCaretaker.addMemento(chessman.save());
    }
 //悔棋
    public void undo(Chessman chessman)
    {
        //得到上一次記錄的備份狀態(tài)對(duì)象
        ChessmanMemento memento = mementoCaretaker.getMemento();
        //調(diào)用恢復(fù)功能
        chessman.restore(memento);
    }
}

測(cè)試

public class Test
{
    public static void main(String[] args) {
        //創(chuàng)建棋子對(duì)象
        Chessman chessman=new Chessman("車(chē)",1,1);
        //創(chuàng)建一個(gè)客戶(hù)端
        Client client=new Client();
        client.play(chessman);
        chessman.show();
        chessman=new Chessman("馬",2,0);
        client.play(chessman);
        chessman.show();
        //悔棋
        client.undo(chessman);
        chessman.show();
        client.undo(chessman);
        chessman.show();
    }
}

在這里插入圖片描述

備忘錄模式總結(jié)

優(yōu)點(diǎn)

  • 它提供了一種狀態(tài)恢復(fù)的實(shí)現(xiàn)機(jī)制,使得用戶(hù)可以方便地回到一個(gè)特定的歷史步驟,當(dāng)新的狀態(tài)無(wú)效或者存在問(wèn)題時(shí),可以使用暫時(shí)存儲(chǔ)起來(lái)的備忘錄將狀態(tài)復(fù)原。
  • 備忘錄實(shí)現(xiàn)了對(duì)信息的封裝,一個(gè)備忘錄對(duì)象是一種原發(fā)器對(duì)象狀態(tài)的表示,不會(huì)被其他代碼所改動(dòng)。備忘錄保存了原發(fā)器的狀態(tài),采用列表、堆棧等集合來(lái)存儲(chǔ)備忘錄對(duì)象可以實(shí)現(xiàn)多次撤銷(xiāo)操作。

缺點(diǎn)

  • 資源消耗過(guò)大,如果需要保存的原發(fā)器類(lèi)的成員變量太多,就不可避免需要占用大量的存儲(chǔ)空間,每保存一次對(duì)象的狀態(tài)都需要消耗一定的系統(tǒng)資源。

適用場(chǎng)景

  • 保存一個(gè)對(duì)象在某一個(gè)時(shí)刻的全部狀態(tài)或部分狀態(tài),這樣以后需要時(shí)它能夠恢復(fù)到先前的狀態(tài),實(shí)現(xiàn)撤銷(xiāo)操作。
  • 防止外界對(duì)象破壞一個(gè)對(duì)象歷史狀態(tài)的封裝性,避免將對(duì)象歷史狀態(tài)的實(shí)現(xiàn)細(xì)節(jié)暴露給外界對(duì)象。

注意細(xì)節(jié)

  • 給用戶(hù)提供了一種可以恢復(fù)狀態(tài)的機(jī)制,可以使用戶(hù)能夠比較方便地回到某個(gè)歷史的狀態(tài)
  • 實(shí)現(xiàn)了信息的封裝,使得用戶(hù)不需要關(guān)心狀態(tài)的保存細(xì)節(jié)
  • 如果類(lèi)的成員變量過(guò)多,勢(shì)必會(huì)占用比較大的資源,而且每一次保存都會(huì)消耗一定的內(nèi)存, 這個(gè)需要注意
  • 適用的應(yīng)用場(chǎng)景:1、后悔藥。 2、打游戲時(shí)的存檔。 3、Windows 里的 ctri + z。4、IE 中的后退。4、數(shù)據(jù)庫(kù)的事務(wù)管理
  • 為了節(jié)約內(nèi)存,備忘錄模式可以和原型模式配合使用

參考文章

備忘錄模式

總結(jié)

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • Java中的ThreadPoolExecutor線(xiàn)程池原理細(xì)節(jié)解析

    Java中的ThreadPoolExecutor線(xiàn)程池原理細(xì)節(jié)解析

    這篇文章主要介紹了Java中的ThreadPoolExecutor線(xiàn)程池原理細(xì)節(jié)解析,ThreadPoolExecutor是一個(gè)線(xiàn)程池,最多可使用7個(gè)參數(shù)來(lái)控制線(xiàn)程池的生成,使用線(xiàn)程池可以避免創(chuàng)建和銷(xiāo)毀線(xiàn)程的資源損耗,提高響應(yīng)速度,并且可以管理線(xiàn)程池中線(xiàn)程的數(shù)量和狀態(tài)等等,需要的朋友可以參考下
    2023-12-12
  • JavaWeb學(xué)習(xí)筆記之Filter和Listener

    JavaWeb學(xué)習(xí)筆記之Filter和Listener

    這篇文章主要給大家介紹了關(guān)于JavaWeb學(xué)習(xí)筆記之Filter和Listener的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Java設(shè)計(jì)模式七大原則之合成復(fù)用原則詳解

    Java設(shè)計(jì)模式七大原則之合成復(fù)用原則詳解

    合成復(fù)用原則(Composite Reuse Principle),即盡量使用組合/聚合的方式,而不是使用繼承。本文將為大家具體介紹一下Java設(shè)計(jì)模式七大原則之一的合成復(fù)用原則,需要的可以參考一下
    2022-02-02
  • java如何實(shí)現(xiàn)字符串中的字母排序

    java如何實(shí)現(xiàn)字符串中的字母排序

    這篇文章主要介紹了java如何實(shí)現(xiàn)字符串中的字母排序問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Eclipse中如何顯示explorer過(guò)程解析

    Eclipse中如何顯示explorer過(guò)程解析

    這篇文章主要介紹了Eclipse中如何顯示explorer過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • JDK12的新特性之teeing collectors

    JDK12的新特性之teeing collectors

    這篇文章主要介紹了JDK12的新特性之teeing collectors的相關(guān)資料,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • springcloud gateway 映射失效的解決方案

    springcloud gateway 映射失效的解決方案

    這篇文章主要介紹了springcloud gateway 映射失效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • jdk17+springboot使用webservice的踩坑實(shí)戰(zhàn)記錄

    jdk17+springboot使用webservice的踩坑實(shí)戰(zhàn)記錄

    這篇文章主要給大家介紹了關(guān)于jdk17+springboot使用webservice踩坑的相關(guān)資料,網(wǎng)上很多教程是基于jdk8的,所以很多在17上面跑不起來(lái),折騰兩天,直接給答案,需要的朋友可以參考下
    2024-01-01
  • java中的BlockingQueue(阻塞隊(duì)列)解析

    java中的BlockingQueue(阻塞隊(duì)列)解析

    這篇文章主要介紹了java中的BlockingQueue阻塞隊(duì)列解析,阻塞隊(duì)列是一個(gè)支持兩個(gè)附加操作的隊(duì)列,這兩個(gè)附加的操作是,在隊(duì)列為空時(shí),獲取元素的線(xiàn)程會(huì)等待隊(duì)列變?yōu)榉强?需要的朋友可以參考下
    2023-12-12
  • JAVA Vector源碼解析和示例代碼

    JAVA Vector源碼解析和示例代碼

    本文的學(xué)習(xí)方式是先對(duì)JAVA Vector有個(gè)整體認(rèn)識(shí),然后再學(xué)習(xí)它的源碼,最后再通過(guò)實(shí)例來(lái)學(xué)會(huì)使用。
    2013-11-11

最新評(píng)論