23种设计模式之备忘录模式
作者:互联网
23种设计模式之备忘录模式
文章目录
参考资料
- Java设计模式:23种设计模式全面解析(超级详细)
- 韩顺平老师的Java设计模式(图解+框架源码剖析)
- 秦小波老师的《设计模式之禅》
下文如有错漏之处,敬请指正
一、简介
定义
记录一个对象的内部状态,并在该对象之外保存这个状态,当需要时能将该对象恢复到原先保存的状态。
特点
- 备忘录模式是一种行为型模式
通用类图
备忘录模式的重要角色:
-
Originator
发起人角色
记录当前时刻的内部状态,定义属于备份范围的状态,提供创建备忘录和恢复备忘录数据的功能。
-
Memento
备忘录角色
负责存储发起人角色的内部状态,实际上是对发起人的内部状态用一个对象(Memento)进行包装。
-
Caretaker
管理员角色
对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
优点
- 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
- 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
- 简化了”发起人“类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。
缺点
- 资源消耗大。如果要保存的内部状态信息过多或备份数量庞大,将会占用比较大的内存资源。
应用场景
- 需要保存与恢复数据的场景,如玩游戏时的当前存档功能。
- 需要提供一个可回滚操作的场景,如 Word、记事本、Photoshop,等软件在编辑时按 Ctrl+Z 组合键,还有数据库中事务操作。
二、实现分类
- 标准备忘录模式
- 多状态多备份的备忘录模式
标准备忘录模式
需求:
模拟用户打字功能,用户按入撤销键可以回到之前的状态,用户按入反撤销键可以回到撤销前的状态,使用备忘录模式实现该功能。
发起人:
package memento.standard;
import java.util.ArrayList;
import java.util.List;
public class Originator {
// 内部状态
private List<String> state = new ArrayList<>();
public List<String> getState() {
return state;
}
public void setState(List<String> state) {
this.state = state;
}
// 创建一个备忘录
public Memento createMemento() {
return new Memento(state);
}
// 恢复一个备忘录
public void restoreMemento(Memento memento) {
this.setState(memento.getState());
}
// ============ 自身业务逻辑=============
// 添加一行内容
public void add(String line) {
state.add(line);
}
// 显示所有的内容
public void display() {
for (String s : state) {
System.out.println(s);
}
}
}
备忘录:
package memento.standard;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class Memento implements Serializable {
// 发起人角色的内部状态
private List<String> State = new ArrayList<>();
// 构造函数传递参数
public Memento(List<String> State) {
this.State = State;
}
public List<String> getState() {
return State;
}
public void setState(List<String> state) {
this.State = state;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
// 通过实现Serializable,对状态进行深克隆
protected Object deepClone() throws Exception {
// 将对象写入流中
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bao);
oos.writeObject(this);
// 将对象从流中取出
ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (ois.readObject());
}
}
管理者:
package memento.standard;
import java.util.Stack;
public class CareTaker {
// 存储 撤销的备忘录对象
private Stack<Memento> memento = new Stack<>();
// 存储 反撤销的备忘录对象
private Stack<Memento> mementoReverse = new Stack<>();
// 添加备忘录对象
public void setMemento(Memento memento) throws Exception {
this.memento.push((Memento) memento.deepClone());
}
// 获取当前撤销备忘录对象,并保存到反撤销备忘录里(即进行Ctrl+Z操作)
public Memento getMemento() {
// 此处的边界处理仅作模式演示,与实际处理不符
if (memento.size() < 0) {
return null;
}
if (memento.size() == 1) {
return mementoReverse.push(memento.pop());
}
mementoReverse.push(memento.pop());
return mementoReverse.push(memento.pop());
}
// 获取当前反撤销备忘录对象,并保存到撤销备忘录里 (即进行Ctrl+Shift+Z操作)
public Memento getMementoReverse() {
// 此处的边界处理仅作模式演示,与实际处理不符
if (mementoReverse.size() < 0) {
return null;
}
if (mementoReverse.size() == 1) {
return memento.push(mementoReverse.pop());
}
memento.push(mementoReverse.pop());
return memento.push(mementoReverse.pop());
}
}
Client:
package memento.standard;
public class Client {
public static void main(String[] args) throws Exception {
// 定义管理员
CareTaker careTaker = new CareTaker();
// 定义发起人
Originator originator = new Originator();
// 发起人添加内容
originator.add("Hello World!");
// 发起人创建一个备忘录
careTaker.setMemento(originator.createMemento());
// 发起人添加新的内容
originator.add("I am in love with you!");
// 发起人创建一个备忘录
careTaker.setMemento(originator.createMemento());
// 发起人添加新的内容
originator.add("bye!");
// 发起人创建一个备忘录
careTaker.setMemento(originator.createMemento());
// 打印当前内容
System.out.println("初始状态");
originator.display();
System.out.println("===============");
// 执行撤销功能
System.out.println("撤销状态");
// 执行第一次撤销
System.out.println("执行第一次撤销");
originator.restoreMemento(careTaker.getMemento());
originator.display();
System.out.println("===============");
// 执行第二次撤销
System.out.println("执行第二次撤销");
originator.restoreMemento(careTaker.getMemento());
originator.display();
System.out.println("===============");
// 执行反撤销功能
System.out.println("反撤销状态");
System.out.println("执行第一次反撤销");
originator.restoreMemento(careTaker.getMementoReverse());
originator.display();
System.out.println("===============");
System.out.println("执行第二次反撤销");
originator.restoreMemento(careTaker.getMementoReverse());
originator.display();
System.out.println("===============");
/**
* 输出结果:
* 初始状态
* Hello World!
* I am in love with you!
* bye!
* ===============
* 撤销状态
* 执行第一次撤销
* Hello World!
* I am in love with you!
* ===============
* 执行第二次撤销
* Hello World!
* ===============
* 反撤销状态
* 执行第一次反撤销
* Hello World!
* I am in love with you!
* ===============
* 执行第二次反撤销
* Hello World!
* I am in love with you!
* bye!
* ===============
*/
}
}
多状态多备份的备忘录模式
需求:
有一个bean对象有多个状态,且可以多次备份该bean对象。
工具类:
package memento.more;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
public class BeanUtils {
// 把bean的所有属性及数值放入到Hashmap中
public static HashMap<String, Object> backupProp(Object bean) {
HashMap<String, Object> result = new HashMap<>();
try {
// 获得bean描述
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
// 获得属性描述
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
// 遍历所有属性
for (PropertyDescriptor descriptor : descriptors) {
// 属性名称
String fieldName = descriptor.getName();
// 读取属性的方法
Method readMethod = descriptor.getReadMethod();
// 读取属性值
Object fieldValue = readMethod.invoke(bean, new Object[]{});
if (!fieldName.equalsIgnoreCase("class")) {
result.put(fieldName, fieldValue);
}
}
} catch (Exception e) {
}
return result;
}
public static void restoreProp(Object bean, HashMap<String, Object> propMap) {
try {
// 获得bean描述
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
// 获得属性描述
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
// 遍历所有属性
for (PropertyDescriptor descriptor : descriptors) {
// 属性名称
String fieldName = descriptor.getName();
// 如果存在该属性
if (propMap.containsKey(fieldName)) {
// 写属性的方法
Method writeMethod = descriptor.getWriteMethod();
writeMethod.invoke(bean, new Object[]{propMap.get(fieldName)});
}
}
} catch (Exception e) {
}
}
}
Originator:
package memento.more;
public class Originator {
// 内部状态
private String state1 = "";
private String state2 = "";
private String state3 = "";
public String getState1() {
return state1;
}
public void setState1(String state1) {
this.state1 = state1;
}
public String getState2() {
return state2;
}
public void setState2(String state2) {
this.state2 = state2;
}
public String getState3() {
return state3;
}
public void setState3(String state3) {
this.state3 = state3;
}
// 创建一个备忘录
public Memento createMemento() {
return new Memento(BeanUtils.backupProp(this));
}
// 恢复一个备忘录
public void restoreMemento(Memento memento) {
BeanUtils.restoreProp(this, memento.getStateMap());
}
@Override
public String toString() {
return "state1=" + state1 + "\nstate2=" + state2 + "\nstate3=" + state3;
}
}
Memento:
package memento.more;
import java.util.HashMap;
public class Memento {
// 使用HashMap存储状态
private HashMap<String, Object> stateMap;
public Memento(HashMap<String, Object> map) {
this.stateMap = map;
}
public HashMap<String, Object> getStateMap() {
return this.stateMap;
}
public void setStateMap(HashMap<String, Object> stateMap) {
this.stateMap = stateMap;
}
}
CareTaker:
package memento.more;
import java.util.HashMap;
public class CareTaker {
// 容纳备忘录的容器
private HashMap<String, Memento> container = new HashMap<>();
public Memento getMemento(String idx) {
return this.container.get(idx);
}
public void setMemento(String idx, Memento memento) {
this.container.put(idx, memento);
}
}
Client:
package memento.more;
public class Client {
public static void main(String[] args) {
// 定义出发起人
Originator originator = new Originator();
// 定义管理员
CareTaker caretaker = new CareTaker();
//初始化
originator.setState1("Huawei");
originator.setState2("Xiaomi");
originator.setState3("honor");
System.out.println("==========初始状态==========");
System.out.println(originator);
// 创建备忘录
caretaker.setMemento("001", originator.createMemento());
// 修改状态值
originator.setState1("Apple");
originator.setState2("Samsung");
originator.setState3("Nokia");
System.out.println("==========修改后的状态==========");
System.out.println(originator);
// 创建备忘录
caretaker.setMemento("002", originator.createMemento());
// 恢复第一个个指定标记的备忘录
originator.restoreMemento(caretaker.getMemento("001"));
System.out.println("==========恢复第一个指定标记的的状态==========");
System.out.println(originator);
// 恢复第二个指定标记的备忘录
originator.restoreMemento(caretaker.getMemento("002"));
System.out.println("==========恢复第二个指定标记的状态==========");
System.out.println(originator);
/**
* ==========初始状态==========
* state1=Huawei
* state2=Xiaomi
* state3=honor
* ==========修改后的状态==========
* state1=Apple
* state2=Samsung
* state3=Nokia
* ==========恢复第一个指定标记的的状态==========
* state1=Huawei
* state2=Xiaomi
* state3=honor
* ==========恢复第二个指定标记的状态==========
* state1=Apple
* state2=Samsung
* state3=Nokia
*/
}
}
三、总结
通俗地说,备忘录模式就是一个对象的备份模式,提供了一种程序数据的备份方法。
标签:originator,23,备忘录,println,设计模式,public,memento,out 来源: https://blog.csdn.net/space_qi/article/details/116357517