设计模式的分类
我们都知道有 23 种设计模式,这 23 种设计模式可分为如下三类:
- 创建型模式(5 种):单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
- 结构型模式(7 种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
- 行为型模式(11 种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
设计模式系列文章传送门
什么是备忘录模式
备忘录模式(Memento Pattern)是一种行为设计模式,它允许在不暴露对象内部状态的情况下保存和恢复对象之前的状态。就像是给对象的状态拍了一张 “快照”,之后可以根据这个 “快照” 将对象恢复到之前的某个状态,所以备忘录模式也叫做快照模式。
备忘录模式的组成部分
- 源发器:需要保存状态的对象,它创建一个备忘录来存储当前状态,并可以使用备忘录来恢复状态。
- 备忘录:用于存储原发器对象的内部状态。备忘录的内容对外界是不可见的,只有原发器能够访问和修改它,它就像是一个黑盒,只负责保存数据。
- 负责人:负责保存备忘录,但不能对备忘录的内容进行操作或访问。它只是起到一个存储和管理备忘录的作用,它可以存储多个备忘录对象,并决定何时将备忘录恢复给源发器。
备忘录模式工作原理
当原发器的状态需要被保存时,它会创建一个备忘录对象,并将自身的状态复制到备忘录中。然后,这个备忘录对象会被传递给负责人进行存储,当需要恢复原发器的状态时,负责人会将相应的备忘录对象返回给原发器,原发器再从备忘录中获取状态信息来恢复自身状态。
备忘录模式案例演示
备忘录模式的场景在我们生活中也十分丰富,例如我们常用的撤销操作、回退操作、回到上一步等等都是比较贴合备忘录场景的,我们使用浏览记录回退来做为备忘录模式的演示案例业务场景。
HistoryMemento(备忘录)
HistoryMemento 有一个浏览器访问地址属性,代码如下:
public class HistoryMemento {
//浏览地址
private String address;
public HistoryMemento(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
HistoryOriginator(源发器)
HistoryOriginator 中也有一个浏览器访问地址属性,并提供了创建备忘录和回退到上一次访问记录的属性,代码如下:
public class HistoryOriginator {
//浏览地址
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
//创建备忘录对象
public HistoryMemento createHistoryMemento(String address) {
return new HistoryMemento(address);
}
//回退到上一次的记录
public void rollbackAddress(HistoryMemento historyMemento) {
address = historyMemento.getAddress();
}
}
HistoryResponsiblePerson(负责人)
HistoryResponsiblePerson 负责提供了管理备忘录的方法,提供了一个添加备忘录和一个移除备忘录的方法,代码如下:
public class HistoryResponsiblePerson {
//备忘录对象数组
private List<HistoryMemento> historyMementoList = new ArrayList<>();
//添加备忘录对象
public void addHistoryMemento(HistoryMemento historyMemento) {
historyMementoList.add(historyMemento);
}
//移除备忘录对象
public HistoryMemento removeHistoryMemento() {
HistoryMemento historyMemento = historyMementoList.get(historyMementoList.size() - 1);
historyMementoList.remove(historyMementoList.size() - 1);
return historyMemento;
}
}
MementoClinet(客户端)
MementoClinet 代码如下:
public class MementoClinet {
public static void main(String[] args) {
//源发器对象
HistoryOriginator historyOriginator = new HistoryOriginator();
//责任人
HistoryResponsiblePerson historyResponsiblePerson = new HistoryResponsiblePerson();
historyOriginator.setAddress("baidu.com/page");
historyResponsiblePerson.addHistoryMemento(historyOriginator.createHistoryMemento("baidu.com/page"));
historyOriginator.setAddress("baidu.com/order");
historyResponsiblePerson.addHistoryMemento(historyOriginator.createHistoryMemento("baidu.com/order"));
historyOriginator.setAddress("baidu.com/info");
System.out.println("当前访问的地址是:" + historyOriginator.getAddress());
historyOriginator.rollbackAddress(historyResponsiblePerson.removeHistoryMemento());
System.out.println("上一次访问的地址是:" + historyOriginator.getAddress());
historyOriginator.rollbackAddress(historyResponsiblePerson.removeHistoryMemento());
System.out.println("再上一次访问的地址是:" + historyOriginator.getAddress());
}
}
执行结果如下:
当前访问的地址是:baidu.com/info
上一次访问的地址是:baidu.com/order
再上一次访问的地址是:baidu.com/page
结果符合预期。
备忘录模式的优缺点
优点:
- 备忘录模式提供了一种简单有效的方式来保存和恢复对象的状态,这在很多场景下非常有用。
- 它将被保存的状态信息封装在备忘录对象中,这样原发器(Originator)对象的内部细节对其他对象(如负责人 Caretaker)是隐藏的。这种封装性符合面向对象设计的原则,有助于保持代码的模块化和低耦合性。
- 当需要对原发器对象的状态保存和恢复功能进行扩展时,比如增加新的状态或者新的恢复方式,在不修改原发器和负责人核心代码的情况下,通过创建新的备忘录类或者对备忘录的存储和恢复策略进行扩展来实现。
缺点:
- 备忘录模式需要额外的资源来存储对象的状态,如果对象的状态信息非常庞大或者频繁地创建备忘录,可能会占用大量的内存空间。
- 何时以及如何清理备忘录是一个比较棘手的问题,备忘录长时间保留,会占用过多资源,但如果过早地清理备忘录,可能会导致无法恢复到某些需要的状态。
备忘录模式的使用场景
- 文本编辑器中的撤销、恢复功能,以及浏览器的回退功能。
- 图形编辑软件中的历史记录功能,用户操作过程中会对图形进行各种操作,而软件需要记录这些操作的历史状态,以便用户可以撤销或恢复特定的操作步骤。
总结:本篇分享了备忘录设计模式的理论概念以及案例演示,备忘录模式的本质就是在不破坏封装性的前提下,捕获和存储一个对象的内部状态,并在需要时将对象恢复到先前的状态,简单来说就是一个快照的功能,本篇也是用代码案例进行了演示,希望可以帮助到不太熟悉备忘录模式的朋友们。
如有不正确的地方欢迎各位指出纠正。