1.定义:在不破坏封装性的前提下,捕获一个对象的部分状态并在该对象之外保存这些状态。这样可以将该对象回复到原先保存的状态
2.UML
3.涉及角色
1.发起人角色:负责创建备忘录,用以记录当前时刻的状态并可食用备忘录回复状态。发起人根据需要可以将部分或者全部信息存储到备忘录中
2.备忘录角色:负责存储发起者角色的状态并可防治除发起者角色之外的对象修改状态。需要注意的是:备忘录角色的状态需要发起者初始化
3.备忘录管理角色:持有备忘录角色实例,管理并保存备忘录角色。需要注意的是:该实例的初始化由发起者完成。
4.优点
1.发起者将需要保存的细节被分装在备忘录角色中,修改保存细节不会影响到客户端
2.某些对象的内部信息需要保存在对象以为的地方,但是必须要由该对象自己读取,该模式可以把复杂对象的内部信息对其他对象屏蔽,保持封装边界
5.缺点
1.如果发起者在生成备忘录时必须复制并存储大量的信息,或者客户非常频繁地创建备忘录和恢复发起者状态,可能会导致非常大的开销。所以在不建议在循环中使用备忘录因为备忘录数量无法控制,如果保存的信息量比较大时,资源的消耗也是问题
2.备份一旦产生就会存储在内存中,没有销毁的意向,建议现在备忘录的上限在一些多备份的场景中可以给备忘录添加上限。同时在恢复原始状态后应该及时清理备忘录中数据,防止备忘录内存溢出或泄漏
7.code
发起者角色
//发起人角色
//只有发起人明确知道备份的状态,需要创建备忘录同时需要将备份的状态存储在备忘录中在必要的时候恢复
public class Originator {
private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Memento createMemento() {
return new Memento(this.status);
}
public String reStoreMemento(Memento memento) {
this.setStatus(memento.getStatus());
return memento.getStatus();
}
}
备忘录角色
//存储发起人需要存储的状态
public class Memento {
private String status;
//该状态必须有发起者角色初始化
public Memento(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
备忘录管理角色
public class Caretaker {
private Memento memento;
public Caretaker(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
客户端
public class Client {
public static void main(String[] args) {
Originator originator = new Originator();
originator.setStatus("before");
System.out.println(originator.getStatus());
Caretaker caretaker = new Caretaker(originator.createMemento());
originator.setStatus("after");
System.out.println(originator.getStatus());
System.out.println(originator.reStoreMemento(caretaker.getMemento()));
}
}
结合clone模式,clone涉及到深浅copy的问题,所以该中方式建议使用在浅copy的场景中。同时需要备份的信息不能严重耦合
UML
Code
发起者角色
public class Originator implements Cloneable {
//用来备份当前对象状态的对象
private Originator backup = null;
private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
//采用clone方式创建当前对象的备份,该备份属于权备份即备份所有的属性
public void createMemento() {
try {
backup = this.clone();
} catch (CloneNotSupportedException e) {
}
}
//采用备份对象恢复状态需要判断nullpointerror
public String restoreMemento() {
this.setStatus(this.backup.status);
return this.backup.status;
}
@Override
public Originator clone() throws CloneNotSupportedException {
backup = (Originator) super.clone();
return backup;
}
}
客户端角色
public class Client {
public static void main(String[] args) {
Originator originator = new Originator();
originator.setStatus("1");
System.out.println(originator.getStatus());
originator.createMemento();
originator.setStatus("2");
System.out.println(originator.getStatus());
String status = originator.restoreMemento();
System.out.println(status);
}
}
保存复杂对象即采用该模式保存javaBean
UML
发起者角色
public class Student implements Serializable {
private String name;
private String sex;
private int age;
private BeanUtils<Object, Object> beanUtils = new BeanUtils<Object, Object>();
public Student() {
}
public Student(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//创建备忘录
public Memento<Object, Object> createMemenote() {
return new Memento(beanUtils.backupProp(this));
}
//恢复状态
public void restoreMemenote(Memento<Object, Object> memento) {
beanUtils.restoreProp(this, memento.getMap());
}
@Override
public String toString() {
return "Name: " + this.name + ", Sex: " + this.sex + ", age: " + this.age;
}
}
备忘录角色
public class Memento<K, V> {
private Map<K, V> map;
public Memento(Map<K, V> map) {
this.map = map;
}
public Map<K, V> getMap() {
return map;
}
public void setMap(Map<K, V> map) {
this.map = map;
}
}
管理者角色
public class Caretaker {
private Memento memento;
public Caretaker(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
工具类
public class BeanUtils<K, V> {
/**
* 备份某个对象的状态
*
* @param v 某个具体对象
* @return
* key:属性名称 value:属性数据
*/
public Map<K,V> backupProp(V v) {
Map<K, V> map = new HashMap<K, V>();
try {
BeanInfo beanInfo = Introspector.getBeanInfo(v.getClass());
//获得某个对象的所有属性
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor descriptor : descriptors) {
//获得属性名称
K k = (K)descriptor.getName();
//获得读取属性的方法一般指getter
Method getter = descriptor.getReadMethod();
//获得属性的状态并将状态和属性名称建立映射
V vv = (V)getter.invoke(v, new Object[]{});
if (!"class".equals(k)) {
map.put(k, vv);
}
}
} catch (Exception e) {
}
return map;
}
/**
* 恢复某个对象的状态
* @param v 某个具体对象
* @param map 对象属性名称和属性值建立的映射集合
*/
public void restoreProp(V v, Map<K, V> map) {
try {
BeanInfo beanInfo = Introspector.getBeanInfo(v.getClass());
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor descriptor : descriptors) {
K k = (K)descriptor.getName();
//集合中是否含有属性名称。如果含有获取该信息并恢复当前对象状态
if(map.containsKey(k)) {
//获得属性的写方法一般指setter
Method setter = descriptor.getWriteMethod();
setter.invoke(v, new Object[]{map.get(k)});
}
}
} catch (Exception e) {
}
}
}
客户端
public class Client {
public static void main(String[] args) {
Student st = new Student("Mark", "M", 18);
System.out.println(st.toString());
Caretaker caretaker = new Caretaker(st.createMemenote());
st.setAge(26);
System.out.println(st.toString());
st.restoreMemenote(caretaker.getMemento());
System.out.println(st.toString());
}
}
发起者
public class Teacher implements Serializable {
private String name;
private String sex;
private int age;
private BeanUtils<Object, Object> beanUtils = new BeanUtils<Object, Object>();
public Teacher() {
}
public Teacher(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//创建备忘录
public TeacherMemento<Object, Object> createMemenote() {
return new TeacherMemento(beanUtils.backupProp(this));
}
//恢复状态
public void restoreMemenote(TeacherMemento<Object, Object> memento) {
beanUtils.restoreProp(this, memento.getMap());
}
@Override
public String toString() {
return "Name: " + this.name + ", Sex: " + this.sex + ", age: " + this.age;
}
}
管理者
public class TeacherCaretake<K, V> {
private Map<K, V> memenote = new HashMap<K, V>();
public V getMemenote(K k) {
return memenote.get(k);
}
public void setMemenote(K k , V v) {
memenote.put(k, v);
}
}
备忘录
public class TeacherMemento<K, V> {
private Map<K, V> map;
public TeacherMemento(Map<K, V> map) {
this.map = map;
}
public Map<K, V> getMap() {
return map;
}
public void setMap(Map<K, V> map) {
this.map = map;
}
}
客户端
public class Client {
public static void main(String[] args) {
Teacher t1 = new Teacher("a", "b", 22);
System.out.println("原始状态:" + t1.toString());
//备份
TeacherCaretake tc = new TeacherCaretake();
tc.setMemenote("t1", t1.createMemenote());
//从新设置
t1.setName("BBB");
System.out.println("新状态:" + t1.toString());
//恢复
t1.restoreMemenote((TeacherMemento)tc.getMemenote("t1"));
System.out.println("恢复状态:" + t1.toString());
}
}
更加安全的访问控制,采用内部类
采用一个类可以实现多个接口的特性,即双接口设计。
出于对象安全的问题。提供两个接口,一个是实际的业务接口,需要定义业务具有的行为提供扩展,该接口叫做宽接口,侧重于行为的继承。
另外一个接口什么方法也没有,其目的是提供给子系统外的模块访问该接口被定义为窄接口。侧重于类型的继承。
UML
发起者角色,采用部内类定义备忘录,实现更加严格的安全访问控制,
public class InnerOriginator {
private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public IMemenote createMemento() {
return new Memenote(this.status);
}
public String reStoreMemento(IMemenote memenote) {
Memenote m = (Memenote) memenote;
this.setStatus(m.getStatus());
return m.getStatus();
}
private class Memenote implements IMemenote {
private String status;
public Memenote(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
}
窄接口,侧重于类型的继承,没有具体的行为,提供子系统外的其他模块访问
public interface IMemenote {
}
管理者,依赖于窄接口。
public class InnerCaretaker {
private IMemenote memenote;
public InnerCaretaker(IMemenote memenote) {
this.memenote = memenote;
}
public IMemenote getMemento() {
return memenote;
}
public void setMemento(IMemenote memenote) {
this.memenote = memenote;
}
}