设计模式之备忘录模式

定义

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

通用类图

设计模式之备忘录模式_第1张图片

具体实现

备忘录模式主要是备份对象某一时间的状态,以供后续可能恢复使用。因此有以下几个角色来实现这一功能:发起人角色 Originator、备忘录角色 Memento 和备忘录管理员角色 Caretaker。

发起人角色就是要备份的对象,它负责定义要备份的范围,还要负责创建和恢复备忘录数据,其具体实现如下:

package com.yrs.memento.standard;

/**
 * @Author: yangrusheng
 * @Description: 发起人角色
 * @Date: Created in 17:28 2020/6/21
 * @Modified By:
 */
public class Originator {
    /**
     * 内部状态
     */
    private String state;
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
    /**
     * 创建一个备忘录
     * @return
     */
    public Memento createMemento() {
        return new Memento(this.state);
    }
    /**
     * 恢复备数据
     * @param memento
     */
    public void restoreMemento(Memento memento) {
        this.setState(memento.getState());
    }
}

备忘录角色的责任就是要存储备份对象的数据,以便在恢复数据时提供数据。其具体实现如下:

package com.yrs.memento.standard;
/**
 * @Author: yangrusheng
 * @Description: 备忘录角色
 * @Date: Created in 17:35 2020/6/21
 * @Modified By:
 */
public class Memento {
    /**
     * 发起人内部状态
     */
    private String state;
    public Memento(String state) {
        this.state = state;
    }
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
}

备忘录管理角色的作用是管理备忘录,提供保存和获取备忘录等功能。简单场景下可能看不出太大作用,但是在复杂场景下,上层模块使用备忘录时就会变得麻烦起来,因此通过一个管理类更容易使用。其具体实现如下:

package com.yrs.memento.standard;

/**
 * @Author: yangrusheng
 * @Description: 备忘录管理员角色
 * @Date: Created in 17:36 2020/6/21
 * @Modified By:
 */
public class Caretaker {
    private Memento memento;
    public Memento getMemento() {
        return memento;
    }
    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}

下面看下场景类如何使用备忘录:

package com.yrs.memento.standard;

/**
 * @Author: yangrusheng
 * @Description:
 * @Date: Created in 18:16 2020/6/21
 * @Modified By:
 */
public class Client {
    public static void main(String[] args) {
        Originator originator = new Originator();
        originator.setState("state1");
        System.out.println("init state: " + originator.getState());
        // 备份
        Caretaker caretaker = new Caretaker();
        caretaker.setMemento(originator.createMemento());
        // 改变状态
        originator.setState("state2");
        System.out.println("changed state: " + originator.getState());
        // 恢复之前状态
        originator.restoreMemento(caretaker.getMemento());
        System.out.println("restore state: " + originator.getState());
    }
}

备忘录模式的使用场景

  • 需要保存和恢复数据的相关状态场景。
  • 提供一个可回滚的操作。
  • 需要监控的副本场景中。
  • 数据库连接的事务事务管理。

注意事项:

  • 备忘录的生命周期。应该建立就要使用,不使用应立刻删除。
  • 备忘录的性能。不要在频繁建立备份的场景中使用备忘录模式。

备忘录模式的扩展

clone 方式的备忘录

发起人角色实现 Cloneable 接口,把备忘录角色和管理者角色都集成到发起人内部,这样就大大简化了备忘录模式的使用。

package com.yrs.memento.clone;

import com.yrs.memento.standard.Memento;

/**
 * @Author: yangrusheng
 * @Description: 发起人角色
 * @Date: Created in 17:28 2020/6/21
 * @Modified By:
 */
public class Originator implements Cloneable {

    private Originator backup;

    /**
     * 内部状态
     */
    private String state;

    public String getState() {
        return state;
    }

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

    /**
     * 创建一个备忘录
     */
    public void createMemento() {
        this.backup = this.clone();
    }

    /**
     * 恢复备数据
     */
    public void restoreMemento() {
        if (this.backup != null) {
            this.setState(this.backup.state);
        }
    }

    /**
     * clone 对象
     * @return
     */
    @Override
    protected Originator clone() {
        try {
            return (Originator) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}

多状态的备忘录模式:

当发起人角色有多个状态时,备忘录角色可以使用 HashMap 来存储多个状态,备份和恢复时需要遍历对象的成员变量来一一取值赋值,这里需要一个工具类来做成员变量的取值和赋值,代码具体实现见:
https://github.com/ByrsH/Design-Patterns/tree/master/Design%20Patterns/src/main/java/com/yrs/memento/moreState, 类图如下:
设计模式之备忘录模式_第2张图片

多备份的备忘录

备忘录管理员使用 HashMap 来保存不同版本的备份,保存和读取都有根据版本来操作。详细代码见:https://github.com/ByrsH/Design-Patterns/tree/master/Design%20Patterns/src/main/java/com/yrs/memento/moreBackups

package com.yrs.memento.moreBackups;

import java.util.HashMap;
import java.util.Map;

/**
 * @Author: yangrusheng
 * @Description: 备忘录管理员角色
 * @Date: Created in 17:36 2020/6/21
 * @Modified By:
 */
public class Caretaker {

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

    public Memento getMemento(String key) {
        return mementoMap.get(key);
    }

    public void setMemento(String key, Memento memento) {
        mementoMap.put(key, memento);
    }
}

备份数据安全性

备份数据是不能被修改的,为了保证其安全性,我们定义一个空备忘录接口,然后在发起人角色内部定义内部类备忘录实现该接口。这样就能保证只有发起人可以修改数据。具体实现见:https://github.com/ByrsH/Design-Patterns/tree/master/Design%20Patterns/src/main/java/com/yrs/memento/security

参考

《设计模式之禅-第2版》

你可能感兴趣的:(面向对象,设计模式)