设计模式系列-备忘录模式-Memento

介绍

我们经常使用的办公软件都有回退功能,你曾想过这样的功能是如何实现的呢?相比软件的回退功能比较复杂,我们还是举个对象状态回退的功能,要回退状态,首先得记录对象的历史状态数据,当回退到某个状态时,能从数据存储的地方恢复到对象状态里。通常我们把对象的状态数据封装起来,外部对象无权访问内部状态,如果状态暴露就易违反封装特性,会对代码的可靠性和扩展性作出妥协。
备忘录模式可以在不破坏对象封装特性的前提下解决我们上面的问题,也不会暴露对象的内部结构。为了更好的理解备忘录模式,我们举个案例来说明,创建一个类,有两个Double 类型的字段,然后基于这两个字段进行数学运算,同时支持回退操作,回到上一个运算结果状态。

备忘录模式详解

备忘录模式的目的是不违反封装原则,去捕获对象的内部状态并把状态存储在外部,将来可以利用存储的数据来恢复对象的状态。
主要参与者如下图:
在这里插入图片描述
** Originator **

  • 创建一个包含自己内部数据的备忘录(Memento)对象
  • 利用备忘录对象来恢复内部状态

** Caretaker **

  • 存储备忘录对象的集合
  • 不对备忘录对象进行操作

当想保存 originator 的某时刻状态时,先获取内部状态然后用来组装 Memento 对象,最后把 memento 对象保存在 Caretaker 对象中的集合里。Memento 对象必须隐藏 originator 的内部数据,只提供get 方法获取值,防止外部对象修改 originator 对象存档的内部状态。

代码实现

public class Originator {

    private double x;
    private double y;
    private String lastUndoSavePoint;
    CareTaker careTaker;

    public Originator(double x, double y, CareTaker careTaker) {
        this.x = x;
        this.y = y;
        this.careTaker = careTaker;
        createSavePoint("initial");
    }

    public void createSavePoint(String savePointName) {
        careTaker.saveMemento(savePointName, new Memento(this.x, this.y));
        this.lastUndoSavePoint = savePointName;
    }

    private void setOriginatorState(String savePointName){
        Memento memento = careTaker.getMemento(savePointName);
        this.x = memento.getX();
        this.y = memento.getY();
    }

    public void undo(){
        setOriginatorState(lastUndoSavePoint);
    }

    public void undo(String savePointName){
        setOriginatorState(savePointName);
    }

    public void undoAll(){
        setOriginatorState("initial");
        careTaker.clearSavePoints();
    }

    public double getX() {
        return x;
    }

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

    public double getY() {
        return y;
    }

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

    @Override
    public String toString() {
        return "Originator{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
}

public class Memento {

    private final double x;
    private final double y;

    public Memento(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return x;
    }

    public double getY() {
        return y;
    }
}

public class CareTaker {

    private final Map<String, Memento> savePointStorage = new HashMap<>();

    public void saveMemento(String savePointName, Memento memento) {
        System.out.println("Save state..." + savePointName);
        savePointStorage.put(savePointName, memento);
    }

    public Memento getMemento(String savePointName) {
        System.out.println("Undo at..." + savePointName);
        return savePointStorage.get(savePointName);
    }

    public void clearSavePoints(){
        System.out.println("Clearing all save points...");
        savePointStorage.clear();
    }
}

public class TestMementoPattern {

    public static void main(String[] args) {
        CareTaker careTaker = new CareTaker();
        Originator originator = new Originator(1, 2, careTaker);
        originator.setY(6);
        originator.createSavePoint("save1");
        originator.undo();
        System.out.println("State: " + originator);
        originator.setX(10);
        originator.createSavePoint("save2");
        originator.setY(11);
        originator.createSavePoint("save3");
        originator.undo("save2");
        System.out.println("State: " + originator);
    }
}

输出结果:

Save state…initial
Save state…save1
Undo at…save1
State: Originator{x=1.0, y=6.0}
Save state…save2
Save state…save3
Undo at…save2
State: Originator{x=10.0, y=6.0}

需要记录某时刻对象状态的快照,并且将来能够复原的场景,需要考虑用备忘录模式,在Jdk 中使用此模式的例子

  • java.util.Date
  • java.io.Serializable
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值