19.备忘录模式

1.什么是备忘录模式?

备忘录模式:在不破坏封装的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。

说人话:游戏存档,或者ctrl+Z的撤回操作

 

备忘录模式是一种对象行为型模式,其别名为标记模式

 

2.备忘录结构

(1)Originator(原发器):原发器是一个普通类,它通过创建一个备忘录来存储当前内部状态,也可以使用备忘录来恢复其内部状态,一般将系统中需要保存内部状态的类设计为原发器

(2)Memento(备忘录)备忘录用于存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用,原发器的设计在不同的编程语言中实现机制会有所不同

(3)Caretaker(负责人):负责人又称为管理者,它负责保存备忘录,但是不能对备忘录的内容进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,它只负责存储对象,而不能修改对象,也无需知道对象的实现细节。

 

3.备忘录实现

(1)原发器

/**
 * 原发器
 */
public class Originator {
    private String state;

    public Originator(String state){
        this.state = state;
    }



    //创建一个备忘录对象
    public Memento createMemento(){
        return new Memento(this);
    }

    //根据备忘录对象恢复原发器状态
    public void restoreMemento(Memento m){
        state = m.state;
    }


    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

(2)备忘录类,默认可见性,包内可见

/**
 * 备忘录类,默认可见性,包内可见
 */
class Memento {
    public String state;

    public Memento(Originator o){
        state = o.getState();
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

(3)负责人类

/**
 * 负责人类
 */
public class Caretaker {
    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}

(4)客户端类

public class Client {
    public static void main(String[] args) {
        //创建原发器对象
        Originator ori = new Originator("状态(1)");
        System.out.println(ori.getState());

        //创建负责人对象,保存创建的备忘录对象
        Caretaker ct = new Caretaker();
        ct.setMemento(ori.createMemento());

        ori.setState("状态(2)");
        System.out.println(ori.getState());

        //从负责人对象中取出备忘录对象,实现撤销
        ori.restoreMemento(ct.getMemento());
        System.out.println(ori.getState());
    }
}

(5)结果及路径

19.备忘录模式_第1张图片

 

4.备忘录实例——象棋悔棋的功能实现

(1)象棋棋子类,充当原发器

/**
 * 象棋棋子类,充当原发器
 */
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.x = memento.getX();
        this.y = memento.getY();
    }


    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;
    }
}

(2)象棋棋子备忘录类,充当备忘录

/**
 * 象棋棋子备忘录类,充当备忘录
 */
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;
    }
}

(3)象棋棋子备忘录管理类,充当负责人

/**
 * 象棋棋子备忘录管理类,充当负责人
 */
public class MementoCaretaker {
    private ChessmanMemento memento;

    public ChessmanMemento getMemento() {
        return memento;
    }

    public void setMemento(ChessmanMemento memento) {
        this.memento = memento;
    }
}

(4)客户端

public class Client {
    public static void main(String[] args) {
        MementoCaretaker mc = new MementoCaretaker();
        Chessman chess = new Chessman("车",1,1);
        display(chess);
        mc.setMemento(chess.save());//保存状态

        chess.setY(4);
        display(chess);
        mc.setMemento(chess.save());//保存状态

        chess.setX(5);
        display(chess);
        System.out.println("----------悔棋-------------");
        chess.restore(mc.getMemento());//恢复状态
        display(chess);

    }

    public static void display(Chessman chess) {
        System.out.println("棋子"+chess.getLabel()+"当前位置为:第"+chess.getX()+"行,第"+chess.getY()+"列");
    }
}

(5)运行结果及路径

19.备忘录模式_第2张图片

 

5.象棋例子——实现多次撤销

(1)象棋棋子类,充当原发器

/**
 * 象棋棋子类,充当原发器
 */
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.x = memento.getX();
        this.y = memento.getY();
    }


    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;
    }
}

(2)象棋棋子备忘录类,充当备忘录

/**
 * 象棋棋子备忘录类,充当备忘录
 */
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;
    }
}

(3)象棋棋子备忘录管理类,充当负责人

/**
 * 象棋棋子备忘录管理类,充当负责人
 */
public class MementoCaretaker {
    //定义一个集合来存储多个备忘录
    private ArrayList mementoArrayList = new ArrayList();

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

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

(4)客户端

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);
        play(chess);
        chess.setX(4);
        play(chess);
        chess.setY(5);
        play(chess);
        undo(chess,index);
        undo(chess,index);
        redo(chess,index);
        redo(chess,index);
    }

    //下棋
    public static void play(Chessman chess){
        mc.setMemento(chess.save());//保存备忘录
        index ++ ;
        System.out.println("棋子"+chess.getLabel()+"当前位置为:第"+chess.getX()+"行,第"+chess.getY()+"列");
    }

    //悔棋
    public static void undo(Chessman chess,int i){
        System.out.println("-------悔棋--------------");
        index --;
        chess.restore(mc.getMemento(i-1));//撤销到上一个备忘录
        System.out.println("棋子"+chess.getLabel()+"当前位置为:第"+chess.getX()+"行,第"+chess.getY()+"列");
    }

    //撤销悔棋
    public static void redo(Chessman chess,int i){
        System.out.println("---------撤销悔棋-------------");
        index++;
        chess.restore(mc.getMemento(i+1));//恢复到下一个备忘录
        System.out.println("棋子"+chess.getLabel()+"当前位置为:第"+chess.getX()+"行,第"+chess.getY()+"列");
    }





}

 

6.备忘录优缺点

优:

(1)实现了状态恢复的实现机制

(2)实现对信息的封装,一个备忘录对象是一种原发器对象状态的标识

缺:

资源消耗过大

 

7.使用环境

(1)保存一个对象在某个时刻的状态,以后能随时恢复

(2)防止外界对象破坏一个对象历史状态的封装性

你可能感兴趣的:(设计模式,设计模式)