1. 程式人生 > >設計模式的藝術 行為型模式之備忘錄模式

設計模式的藝術 行為型模式之備忘錄模式

前言

每個人都會有後悔的時候,可是人生沒有後悔藥,做過的事情無法再去後悔,軟體設計中卻是有這麼一種後悔機制,叫做備忘錄模式,它就是軟體中的"後悔藥"

什麼是備忘錄模式  Memento Pattern

在不破壞封裝的前提下,捕獲一個物件的內部狀態,並在物件之外儲存這個狀態,這樣可以將物件恢復到原先儲存的狀態,它是一種物件行為型模式,有個別名叫做Token

備忘錄模式的優點

(1)、它提供了一種狀態恢復的實現機制,使得使用者可以方便地回到一個特定的歷史步驟,當新的狀態無效或者存在問題時,可以使用暫時儲存的備忘錄將狀態復原

(2)、備忘錄實現了對資訊的封裝,一個備忘錄物件是一種原發器物件狀態的表示,不會被其他程式碼所改動,備忘錄儲存了原發器的狀態,採用列表,堆疊等集合來儲存備忘錄物件可以實現多次撤銷操作。

備忘錄模式的主要缺點

資源消耗過大,如果需要儲存的原發器類的成員變數太多,就不可避免地需要佔用大量的儲存空間,每儲存一次物件的狀態都需要消耗一定的系統資源。

備忘錄模式的適用場景

(1)、儲存一個物件在某一個時刻的全部狀態或部分狀態,這樣以後需要時就能恢復到先前的狀態,實現撤銷操作

(2)、防止外界物件破壞一個物件歷史狀態的封裝性,避免將物件歷史狀態的實現細節暴露給外界物件

備忘錄模式的具體實現

目錄結構

原發器

package com.company;

//象棋棋子類:原發器
public class Chessman {
    private  String label;
    private int x;
    private int y;

    public Chessman(String label, int x, int y) {
        this.label = label;
        this.x = x;
        this.y = y;
    }
    //儲存狀態
    public ChessmanMemento save(){
        return  new ChessmanMemento(this.label,this.x,this.y);
    }
    //恢復狀態
    public void restore(ChessmanMemento memento){
        this.label=memento.getLabel();
        this.y=memento.getY();
        this.x=memento.getX();
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}

備忘錄

package com.company;

//棋子備忘錄
public class ChessmanMemento {
    private  String label;
    private int x;
    private int y;

    public ChessmanMemento(String label, int x, int y) {
        this.label = label;
        this.x = x;
        this.y = y;
    }


    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}

備忘錄管理類

package com.company;

import java.util.ArrayList;

//象棋棋子備忘錄管理類:負責人
public class MementoCaretaker {
/*    private ChessmanMemento memento;

    public ChessmanMemento getMemento() {
        return memento;
    }

    public void setMemento(ChessmanMemento memento) {
        this.memento = memento;
    }*/
//定義一個集合來儲存多個備忘錄
    private ArrayList mementoList=new ArrayList();

    public ChessmanMemento getMemento(int i) {
        return (ChessmanMemento) mementoList.get(i);
    }

    public void setMemento(ChessmanMemento memento) {
        mementoList.add(memento);
    }
}

測試類

package com.company;

public class Client {
    private static int index = -1;  //定義一個索引來記錄當前狀態所在的位置
    private static MementoCaretaker mc = new MementoCaretaker();

    public static void main(String[] args) {
        Chessman chess = new Chessman("車", 1, 1);
        display(chess);
        chess.setX(4);
        display(chess);
        chess.setX(5);
        display(chess);
        undo(chess, index);
        undo(chess, index);
        redo(chess, index);
        redo(chess, index);
    }

    //撤銷悔棋
    private static void redo(Chessman chess, int index) {
        System.out.println("撤銷悔棋");
        index++;
        chess.restore(mc.getMemento(index+1));  //恢復到下一個備忘錄
        System.out.println("棋子" + chess.getLabel() + "當前位置為:" + "第" + chess.getX() + "行" + "第" + chess.getY() + "行。");
    }
    //悔棋
    private static void undo(Chessman chess, int index) {
        System.out.println("悔棋");
        index--;
        chess.restore(mc.getMemento(index-1));  //撤銷到上個備忘錄
        System.out.println("棋子" + chess.getLabel() + "當前位置為:" + "第" + chess.getX() + "行" + "第" + chess.getY() + "行。");
    }

    private static void display(Chessman chess) {
        mc.setMemento(chess.save());  //儲存在備忘錄
        index++;
        System.out.println("棋子" + chess.getLabel() + "當前位置為:" + "第" + chess.getX() + "行" + "第" + chess.getY() + "行。");
    }
}

轉載請註明出處,掌聲送給社會人