标准 专业
多元 极客

设计模式实验室(24)——备忘录模式

什么是备忘录模式?

备忘录模式是一种对象行为型模式。

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

备忘录模式相当于对对象的内部状态进行实时记录,以便在未来需要时,可以任意读档

既然说到读档,那么其实单机游戏中的存档,棋类游戏中的悔棋,其实都是备忘录模式的具体实现。

核心结构

  • Originator。原发器,普通类,可以使用它创建一个备忘录,并存储它的内部状态,也可以从这个备忘录中取出它的内部状态并进行恢复,一般我们会将保存内部状态的类设计为原发器。
  • Memento。备忘录,存储原发器的内部状态,根据原发器来决定需要保存的内部状态,备忘录的设计一般可以参考原发器的设计,并根据实际需要确定备忘录中的属性,备忘录对象不对外暴露。
  • Caretaker。负责人,负责保存备忘录,但是不能对备忘录的内容进行操作或检查。负责人中可以存在多个备忘录,它只负责存储备忘录。

类图展示

备忘录模式

代码分析

中国象棋历史悠久,经常对弈,可以提高人的各方面能力。我们在网络上对弈时,没进行一步,计算机都会有记载的,随时方便我们复盘或者悔棋,当然我们是不建议经常悔棋的,毕竟君子一出,驷马难追。

首先我们先设计一个原发器,用它来获取或更新备忘录的状态:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/30.
 * 备忘录模式——原发器
 */
public class ChineseChess {

    private String piece;

    private Integer x;

    private Integer y;

    public ChineseChess(String piece, Integer x, Integer y) {
        this.piece = piece;
        this.x = x;
        this.y = y;
    }

    public String getPiece() {
        return piece;
    }

    public Integer getX() {
        return x;
    }

    public Integer getY() {
        return y;
    }

    public Memento move() {
        return new Memento(this.piece, this.x, this.y);
    }

    public void undo(Memento memento) {
        this.piece = memento.getPiece();
        this.x = memento.getX();
        this.y = memento.getY();
    }
}

接下来我们就需要声明备忘录,用来存储象棋的每一步:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/30.
 * 备忘录模式——备忘录
 */
public class Memento {

    private String piece;

    private Integer x;

    private Integer y;

    public Memento(String piece, Integer x, Integer y) {
        this.piece = piece;
        this.x = x;
        this.y = y;
    }

    public String getPiece() {
        return piece;
    }

    public void setPiece(String piece) {
        this.piece = piece;
    }

    public Integer getX() {
        return x;
    }

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

    public Integer getY() {
        return y;
    }

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

最后我们就需要一个负责人,用它来保存备忘录:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/30.
 * 备忘录模式——负责人
 */
public class Responsibility {

    private Stack<Memento> mementoStack = new Stack<Memento>();

    public Memento getMemento() {
        if (mementoStack.capacity() == 1) {
            System.out.println("undo forbidden");
            return new Memento("begin", 0, 0);
        } else {
            mementoStack.pop();
            return mementoStack.pop();
        }
    }

    public void setMemento(Memento memento) {
        mementoStack.push(memento);
    }
}

惯例,测试代码:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/6/21.
 * 备忘录模式测试
 */
public class MementoTest {

    public static void main(String[] args) {
        Responsibility responsibility = new Responsibility();
        ChineseChess chineseChess = new ChineseChess("炮", 1, 5);
        display(chineseChess);
        responsibility.setMemento(chineseChess.move());
        chineseChess = new ChineseChess("车", 2, 9);
        display(chineseChess);
        responsibility.setMemento(chineseChess.move());
        chineseChess.undo(responsibility.getMemento());
        display(chineseChess);
    }

    private static void display(ChineseChess chineseChess) {
        System.out.println(String.format("棋子:%s,第%s行,第%s列", chineseChess.getPiece(), chineseChess.getX(), chineseChess.getY()));
    }
}

模式总结

优点

  • 提供了状态容器,方便获取或恢复对象的历史状态。

缺点

  • 对资源消耗过大,因为在使用过程中,可能需要保存大量的对象状态,这些对象状态短时间内可能无法释放,对堆内存及系统性能造成了一定的影响。

适用场景

  • 需要保存对象的历史状态,以便未来对其进行获取或者恢复。
  • 历史状态不暴露给外界,保证了对象历史状态的安全性。
赞(0) 投币

评论 抢沙发

慕勋的实验室慕勋的研究院

码字不容易,路过请投币

支付宝扫一扫

微信扫一扫