前言:
为什么之前写过Golang 版的设计模式,还在重新写Java
版?
答:因为对于我而言,当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言,更适合用于学习设计模式。
为什么类图要附上uml
因为很多人学习有做笔记的习惯,如果单纯的只是放一张图片,那么学习者也只能复制一张图片,可复用性较低,附上uml,方便有新理解时,快速出新图。
🔥[设计模式Java实现附plantuml源码]专链
- 创建型
- 确保对象的唯一性~单例模式
- 集中式工厂的实现~简单工厂模式
- 多态工厂的实现——工厂方法模式
- 产品族的创建——抽象工厂模式
- 对象的克隆~原型模式
- 复杂对象的组装与创建——建造者模式
- 结构型
- 提供统一入口——外观模式
- 扩展系统功能——装饰模式
- 树形结构的处理——组合模式
- 对象的间接访问——代理模式
- 不兼容结构的协调——适配器模式
- 处理多维度变化——桥接模式
- 实现对象的复用——享元模式
- 行为型
-
请求的链式处理——职责链模式
-
请求发送者与接收者解耦——命令模式
-
遍历聚合对象中的元素——迭代器模式
-
协调多个对象之间的交互——中介者模式
-
对象间的联动~观察者模式
-
撤销功能的实现——备忘录模式
备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤。当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原。当前很多软件都提供了撤销(Undo)操作,其中就使用了备忘录模式。
备忘录模式定义如下:备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对象行为型模式,其别名为Token。
备忘录模式的核心是备忘录类以及用于管理备忘录的负责人类的设计,其结构如图所示。
@startuml
class Memento {
- state
+ gettersetter()
}
class Caretaker {
}
class Originator {
- state
+ createMemento()
+ restoreMemento(Memento memento)
}
note left of Originator::createMemento
return new Memento;
end note
note left of Originator::restoreMemento
memento.getState()
end note
Originator ..right.>Memento
Caretaker *-up-> Memento: memento
@enduml
由图可以看出,在备忘录模式结构图中包含以下3个角色。
(1)Originator(原发器):它是一个普通类,可以创建一个备忘录,并存储其当前内部状态,也可以使用备忘录来恢复其内部状态。一般将需要保存内部状态的类设计为原发器。
(2)Memento(备忘录):存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用。原发器的设计在不同的编程语言中实现机制会有所不同。
(3)Caretaker(负责人):负责人又称为管理者,他负责保存备忘录,但是不能对备忘录的内容进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,他只负责存储对象,而不能修改对象,也无须知道对象的实现细节。
理解备忘录模式并不难,但关键在于如何设计备忘录类和负责人类。由于在备忘录中存储的是原发器的中间状态,因此需要防止原发器以外的其他对象访问备忘录,特别是不允许其他对象来修改备忘录。
简单代码实现
package behavior;
import java.util.Stack;
public class MementoDemo {
// Memento class
public record Memento(String state){}
// Caretaker class
public static class Caretaker {
private final Stack<Memento> mementoStack = new Stack<>();
public void saveMemento(Memento memento) {
mementoStack.push(memento);
}
public Memento restoreMemento() {
return mementoStack.pop();
}
}
// Originator class
public static class Originator {
private String state;
public Memento createMemento() {
return new Memento(state);
}
public void restoreMemento(Memento memento) {
this.state = memento.state();
}
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// Client code
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("s1");
System.out.println("1 " + originator.getState());
caretaker.saveMemento(originator.createMemento());
originator.setState("s2");
System.out.println("2 " + originator.getState());
caretaker.saveMemento(originator.createMemento());
originator.setState("s3");
System.out.println("3 " + originator.getState());
originator.restoreMemento(caretaker.restoreMemento());
System.out.println("4 " + originator.getState());
originator.restoreMemento(caretaker.restoreMemento());
System.out.println("5 " + originator.getState());
}
}
结果
1 s1
2 s2
3 s3
4 s2
5 s1
总结
备忘录模式在很多软件的使用过程中普遍存在,但是在应用软件开发中,它的使用频率并不太高,因为现在很多基于窗体和浏览器的应用软件并没有提供撤销操作。如果需要为软件提供撤销功能,备忘录模式无疑是一种很好的解决方案。在一些字处理软件、图像编辑软件、数据库管理系统等软件中备忘录模式都得到了很好的应用。
主要优点
备忘录模式的主要优点如下:
(1)它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤。当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原。
(2)备忘录实现了对信息的封装。一个备忘录对象是一种原发器对象状态的表示,不会被其他代码所改动。备忘录保存了原发器的状态,采用列表、堆栈等集合来存储备忘录对象可以实现多次撤销操作。
主要缺点
备忘录模式的主要缺点是:资源消耗过大。如果需要保存的原发器类的成员变量太多,就不可避免地需要占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源。
适用场景
在以下情况下可以考虑使用备忘录模式:
(1)保存一个对象在某一个时刻的全部状态或部分状态,这样以后需要时就能够恢复到先前的状态,实现撤销操作。
(2)防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态的实现细节暴露给外界对象。
🚀 作者简介:作为某云服务提供商的后端开发人员,我将在这里与大家简要分享一些实用的开发小技巧。在我的职业生涯中积累了丰富的经验,希望能通过这个博客与大家交流、学习和成长。技术栈:Java、Golang、PHP、Python、Vue、React
本文收录于三木的
💐 「设计模式」专栏
此外三木还有以下专栏在同步更新~
🌼 「AI」专栏
🔥「面试」这个专栏的灵感来自于许多粉丝私信,大家向我咨询有关面试的问题和建议。我深感荣幸和责任,希望通过这个专栏,能够为大家提供更多关于面试的知识、技巧和经验。我们将一起探讨面试。期待粉丝们ssp的offer喜讯。
🎈 「Java探索者之路」系列专栏,这个专栏旨在引领Java开发者踏上一段真正探索Java世界的旅程。
我们将深入探讨Java编程的方方面面,从基础知识到高级技巧,从实践案例到最新趋势,帮助你成为一名卓越的Java探索者。如果有想进入Java后端领域工作的同学,这个专栏会对你有所帮助,欢迎关注起来呀
🌊 「Python爬虫」的入门学习系列,大家有兴趣的可以看一看
🌹一起学习,互三互访,顺评论区有访必回,有关必回!!!