Java设计模式之备忘录模式

概念和作用

备忘录模式是一种行为设计模式,它让你能够保存一个对象的内部状态,以便在适当的时候恢复对象的先前状态。其主要作用是提供了一种可以恢复对象内部状态而不破坏封装性的机制。

使用场景

备忘录模式适用于需要保存一个对象的状态快照,以便在将来恢复到这个状态的场景。例如,在文本编辑器中实现撤回(undo)功能,游戏中的存档与读档功能,以及在需要事务管理的系统中用于回滚操作等。

示例

1.发起人(即被备份的)类

复制代码
public class Originator {
    private String text;

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

    // 创建备忘录,保存当前状态
    public Memento createMemento() {
        return new Memento(text);
    }

    // 恢复备忘录,恢复到之前的状态
    public void restoreMemento(Memento memento) {
        this.text = memento.getText();
    }

    // 获取和设置文本内容
    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

2.备忘录类

复制代码
public class Memento {
    private final String text;

    public Memento(String text) {
        this.text = text;
    }

    // 获取文本内容
    public String getText() {
        return text;
    }
}

3.管理者类

复制代码
import java.util.ArrayList;
import java.util.List;

public class Caretaker {
    private List<Memento> mementos = new ArrayList<>();

    // 保存备忘录
    public void addMemento(Memento memento) {
        mementos.add(memento);
    }

    // 获取指定索引的备忘录
    public Memento getMemento(int index) {
        if (index >= 0 && index < mementos.size()) {
            return mementos.get(index);
        }
        return null;
    }

    // 获取备忘录数量
    public int getMementoCount() {
        return mementos.size();
    }

    // 清除所有备忘录
    public void clearMementos() {
        mementos.clear();
    }
}

4.客户端代码示例

复制代码
public class Client {
    public static void main(String[] args) {
        Originator originator = new Originator("初始文本内容");
        Caretaker caretaker = new Caretaker();

        // 保存当前状态到备忘录
        caretaker.addMemento(originator.createMemento());
        System.out.println("保存状态到备忘录: " + originator.getText());

        // 修改文本内容
        originator.setText("新的文本内容");
        System.out.println("修改后的文本内容: " + originator.getText());

        // 再次保存状态到备忘录
        caretaker.addMemento(originator.createMemento());
        System.out.println("保存状态到备忘录: " + originator.getText());

        // 修改文本内容
        originator.setText("再次修改的文本内容");
        System.out.println("修改后的文本内容: " + originator.getText());

        // 恢复到上一个状态
        if (caretaker.getMementoCount() > 0) {
            originator.restoreMemento(caretaker.getMemento(caretaker.getMementoCount() - 1));
            System.out.println("恢复到上一个状态: " + originator.getText());
        }

        // 恢复到初始状态
        if (caretaker.getMementoCount() > 1) {
            originator.restoreMemento(caretaker.getMemento(0));
            System.out.println("恢复到初始状态: " + originator.getText());
        }
    }
}

优缺点

优点

1.封装性:它将发起人对象的状态封装在备忘录对象中,外界无法访问备忘录对象中的状态信息,从而保证了发起人对象的封装性。

2.简单易用:备忘录模式提供了一种简单且有效的保存和恢复对象状态的机制,易于理解和使用。

3.灵活的恢复机制:通过备忘录管理器,可以灵活地保存多个状态,并根据需要恢复到任意一个之前的状态。

缺点

1.资源消耗:如果对象的状态信息很多,那么保存每个状态的备忘录对象会占用较多的内存资源,可能导致性能问题。

2.管理复杂性:随着保存的备忘录数量增加,管理和维护这些备忘录可能会变得复杂,需要考虑如何有效地存储和检索备忘录。

不使用备忘录模式的实现

如果不使用备忘录模式,可以通过在发起人对象中直接维护一个历史记录列表来实现类似的功能。例如:

复制代码
import java.util.ArrayList;
import java.util.List;

public class OriginatorWithoutMemento {
    private String text;
    private List<String> history = new ArrayList<>();

    public OriginatorWithoutMemento(String text) {
        this.text = text;
    }

    // 保存当前状态到历史记录
    public void saveState() {
        history.add(text);
    }

    // 恢复到上一个状态
    public void restorePreviousState() {
        if (!history.isEmpty()) {
            text = history.remove(history.size() - 1);
        }
    }

    // 获取和设置文本内容
    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

在客户端代码中,可以这样使用:

复制代码
public class ClientWithoutMemento {
    public static void main(String[] args) {
        OriginatorWithoutMemento originator = new OriginatorWithoutMemento("初始文本内容");

        // 保存当前状态
        originator.saveState();
        System.out.println("保存状态到历史记录: " + originator.getText());

        // 修改文本内容
        originator.setText("新的文本内容");
        System.out.println("修改后的文本内容: " + originator.getText());

        // 再次保存状态
        originator.saveState();
        System.out.println("保存状态到历史记录: " + originator.getText());

        // 修改文本内容
        originator.setText("再次修改的文本内容");
        System.out.println("修改后的文本内容: " + originator.getText());

        // 恢复到上一个状态
        originator.restorePreviousState();
        System.out.println("恢复到上一个状态: " + originator.getText());

        // 恢复到初始状态
        originator.restorePreviousState();
        System.out.println("恢复到初始状态: " + originator.getText());
    }
}

这种方式虽然也能实现类似的功能,但它将状态保存和恢复的逻辑与发起人对象紧密耦合在一起,违反了单一职责原则。

而且,如果需要更复杂的管理功能(如限制保存的历史记录数量、根据特定条件恢复等),会使发起人对象的代码变得更加复杂。

相比之下,备忘录模式通过将状态保存和恢复的职责分离到独立的类中,提供了更清晰、灵活和可扩展的解决方案。

相关推荐
SummerGao.3 分钟前
【实操】Mybatis-plus2.x升级到3.x
java·spring boot·mybatisplus·系统升级
珹洺5 分钟前
C++从入门到实战(五)类和对象(第一部分)为什么有类,及怎么使用类,类域概念详解(附带图谱等更好对比理解)
java·c语言·开发语言·数据结构·c++·redis·缓存
就改了6 分钟前
SpringMVC 跨域问题两种常用解决方案
java·springmvc
凌乱的程序猿8 分钟前
安装和部署Tomcat并在idea创建web文件
java·前端·tomcat
为美好的生活献上中指34 分钟前
java每日精进 3.21 【SpringBoot规范2.0】
java·开发语言·spring boot·log4j·async·mail
kkk哥40 分钟前
基于springboot的教师工作量管理系统(031)
java·spring boot·后端
可了~41 分钟前
SpringBoot的配置文件了解
java·spring boot·后端
碧海饮冰42 分钟前
招聘面试季--一文顿悟,Java中字节流和字符流的区别及使用场景上的差异
java·开发语言·面试
xxjiaz1 小时前
蓝桥每日打卡--区间移位
java·数据结构·算法·蓝桥杯
kiwixing1 小时前
Oracle ASM 磁盘组冗余策略
java·linux·运维·数据库·c++·python·oracle