《设计模式入门》 21.备忘录模式

备忘录模式就是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。

我们在很多地方可以看到版本快照,很多都是使用的备忘录模式来进行版本的管理。

备忘录模式一般分为三个大类:

  • 发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
  • 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
  • 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。

========================================================================

我们对于备忘录模式接触的最多的,就是事务的回滚机制,比如mysql的事务回滚是基于日志进行回滚,我们模仿回滚机制来实现一个备忘录模式:

我们首先定义一个日志文档类,就是我们需要去回滚的日志:

package BehavioralPatterns.MementoPattern;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName LogFile.java
 * @Description 日志文档
 * @createTime 2022年03月17日 16:09:00
 */
public class LogFile {
    private String versionNumber;
    private String updateDate;
    private String doc;
    private String changeDate;
    private String operator;

    public LogFile(String versionNumber,String updateDate,String doc,String changeDate,String operator){
        this.changeDate = changeDate;
        this.doc = doc;
        this.operator = operator;
        this.updateDate = updateDate;
        this.versionNumber = versionNumber;
    }

    public String getChangeDate() {
        return changeDate;
    }

    public String getOperator() {
        return operator;
    }

    public String getUpdateDate() {
        return updateDate;
    }

    public String getVersionNumber() {
        return versionNumber;
    }

    public void setChangeDate(String changeDate) {
        this.changeDate = changeDate;
    }

    public void setOperator(String operator) {
        this.operator = operator;
    }

    public void setUpdateDate(String updateDate) {
        this.updateDate = updateDate;
    }

    public void setVersionNumber(String versionNumber) {
        this.versionNumber = versionNumber;
    }

    public String getDoc() {
        return doc;
    }

    public void setDoc(String doc) {
        this.doc = doc;
    }

    @Override
    public String toString() {
        return "LogFile{" +
                "版本号:='" + versionNumber + '\'' +
                ", 上传时间:='" + updateDate + '\'' +
                ", 日志内容:='" + doc + '\'' +
                ", 修改时间:='" + changeDate + '\'' +
                ", 操作人:='" + operator + '\'' +
                '}';
    }
}

创建一个备忘录,来对日志进行操作:

package BehavioralPatterns.MementoPattern;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName Memento.java
 * @Description 备忘录类
 * @createTime 2022年03月17日 16:19:00
 */
public class Memento {

    private LogFile logFile;

    public Memento (LogFile logFile){
        this.logFile = logFile;
    }

    /**
     * 获取日志
     * @return 日志文档
     */
    public LogFile getLogFile() {
        return logFile;
    }

    /**
     * 设置日志文档
     * @param logFile 日志文档
     */
    public void setLogFile(LogFile logFile) {
        this.logFile = logFile;
    }
}

定义一个记录者:

package BehavioralPatterns.MementoPattern;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName Originator.java
 * @Description 记录者类
 * @createTime 2022年03月17日 16:21:00
 */
public class Originator {
    private LogFile logFile;

    /**
     * 获取日志文件
     * @return 日志文件
     */
    public LogFile getLogFile() {
        return logFile;
    }

    public void setLogFile(LogFile logFile) {
        this.logFile = logFile;
    }

    /**
     * 保存备忘录
     * 保存备忘录的时候会创建一个备忘录信息,并返回回去,交给管理者处理。
     * @return 新建备忘录信息
     */
    public Memento saveMemento(){
        return new Memento(logFile);
    }

    /**
     * 获取备忘录
     * 获取的之后并不是直接返回,而是把备忘录的信息交给现在的文件 this.logFile
     * @param memento 备忘录
     */
    public void getMemento(Memento memento){
        this.logFile = memento.getLogFile();
    }
}

记录者除了可以获取和设置日志,还增加了保存备忘录和获取备忘录的功能。

创建一个日志管理员来记录文件信息:

package BehavioralPatterns.MementoPattern;

import javax.jws.Oneway;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName Caretaker.java
 * @Description 管理员类
 *                  记录文件信息
 * @createTime 2022年03月17日 16:26:00
 */
public class Caretaker {
    private int cursorIndex = 0;
    private final List<Memento> mementos = new ArrayList<Memento>();
    private final Map<String,Memento> mementoMap = new HashMap<String,Memento>();

    /**
     * 添加备忘录
     * @param memento 备忘录
     */
    public void append(Memento memento){
        //把当前备忘录添加到备忘录数组
        mementos.add(memento);
        //把当前备忘录添加到备忘录map,key是现在的版本号,value是对应的备忘录
        mementoMap.put(memento.getLogFile().getVersionNumber(),memento);
        cursorIndex++;
    }

    /**
     * 回滚备忘录
     * @return 回滚的备忘录
     */
    public Memento undoLog(){
        if (--cursorIndex <= 0) {
            return mementos.get(0);
        }
        return mementos.get(cursorIndex);
    }

    /**
     * 撤销回滚
     * @return 返回回滚之前备忘录
     */
    public Memento redoLog(){
        if (++cursorIndex>mementos.size()){
            return mementos.get(mementos.size()-1);
        }
        return mementos.get(cursorIndex);
    }

    /**
     * 定向获取备忘录
     * @param version 备忘录版本号
     * @return 对应的备忘录
     */
    public Memento get(String version){
        return mementoMap.get(version);
    }
}

管理员的核心功能就是记录配置文件信息,也就是备忘录的效果,之后提供可以回滚和获取的方法,拿到备忘录的具体内容。

 测试一下:

package BehavioralPatterns.MementoPattern;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName MementoTest.java
 * @Description 测试类
 * @createTime 2022年03月17日 16:45:00
 */
public class MementoTest {
    public static void main(String[] args) {
        //创建一个管理员
        Caretaker caretaker = new Caretaker();
        //创建一个记录者
        Originator originator = new Originator();

        //添加log
        originator.setLogFile(new LogFile("00001","20211211","喵喵喵喵喵","20211211","张三"));
        //保存log
        caretaker.append(originator.saveMemento());

        originator.setLogFile(new LogFile("00002","20211211","汪汪汪汪汪","20211211","张三"));
        caretaker.append(originator.saveMemento());

        originator.setLogFile(new LogFile("00003","20211211","嘎嘎嘎嘎嘎","20211211","张三"));
        caretaker.append(originator.saveMemento());

        originator.setLogFile(new LogFile("00004","20211211","咕咕咕咕咕","20211211","张三"));
        caretaker.append(originator.saveMemento());

        System.out.println("开始回滚===============");
        originator.getMemento(caretaker.undoLog());
        System.out.println(originator.getLogFile());

        System.out.println("开始回滚===============");
        originator.getMemento(caretaker.undoLog());
        System.out.println(originator.getLogFile());

        System.out.println("开始撤销回滚===============");
        originator.getMemento(caretaker.redoLog());
        System.out.println(originator.getLogFile());

        System.out.println("开始获取版本:00002===============");
        originator.getMemento(caretaker.get("00002"));
        System.out.println(originator.getLogFile());
    }
}

 

优点 :

  1. 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
  2. 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
  3. 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。

缺点:

  1. 资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PigeonEssence

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值