设计模式(十八)—备忘录模式
最后更新于:2022-04-01 16:26:32
**定义**:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将
该对象恢复到原先保存的状态。
## 一般模式:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-06_5755340c961b6.jpg)
Originator发起人角色
---|记录当前时刻的内部状态,负责定义那些属于备份范围的状态,负责创建和恢复备忘录数据
Memento备忘录角色
---|负责存储Originator发起人对象的内部状态,在需要的时候提供发起人需要的内部状态
Caretaker备忘录管理员角色
---|对备忘录进行管理、保存和提供备忘录。
~~~
public class MementoTest {
public static void main(String[] args) {
//定义一个备忘录的发起者
Originator origin = new Originator();
origin.setState("你好!");
//定义一个备忘录的管理者
Caretaker care = new Caretaker();
//创建一个备忘录
care.setMemento(origin.createMemento());
origin.setState("去死吧!");
//恢复原有的数据
origin.restoreMemento(care.getMemento());
System.out.println(origin.getState());
}
}
/**
* 备忘录发起人的角色,
* 备忘录中保存的就是该类的内容。
* @author admin
*
*/
class Originator{
//一个String类型表示当前状态
private String state = "";
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
//创建一个备忘录角色,用于时刻存储数据。
public Memento createMemento(){
return new Memento(this.state);
}
//回复原来的数据
public void restoreMemento(Memento memento){
this.setState(memento.getState());
}
}
/**
* 备忘录角色,
* 该类用于备份、存储原有数据。
* @author admin
*
*/
class Memento{
//一个String类型表示当前状态
private String state = "";
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
/**
* 备忘录的管理类
* 对备忘录进行管理、保存和存储
* @author admin
*/
class Caretaker{
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
~~~
## 一个例子:
模拟月光宝盒中,至尊宝阻止白晶晶自杀的桥段。当白晶晶在洞内自杀,至尊宝没有来得及救,于是就使用月光宝盒--菠萝菠萝蜜
任何就回到上一个状态,继续去救白晶晶,知道能够成功救到为止。
这个例子可以说明,救白晶晶之前,首先保存一个状态命名为1,从这一状态出发,如果没有成功,就回到1状态。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-06_5755340cb924d.jpg)
~~~
public class MementoT {
public static void main(String[] args) {
//创建一个发起者,(看见白晶晶在自杀)
SaveLifeAction action = new SaveLifeAction();
action.setState("白晶晶被至尊宝伤透了心...准备拿剑抹脖子自杀");
//月关宝盒时刻记录每一瞬间
BoxManager boxManager = new BoxManager();
boxManager.setBoxMemento(action.createMemento());
action.setState("白晶晶自杀死了...");
System.out.println(action.getState());
System.out.println("---至尊宝拿着月关宝盒,回去救她----");
//至尊宝拿着月关宝盒,回去救她
action.restoreMemento(boxManager.getBoxMemento());
//回到上一状态
System.out.println(action.getState());
action.setSuccess(true);
if(action.isSuccess()){
System.out.println("----白晶晶成功获救!");
}
}
}
/**
* 该类是发起者类,
* 设置负责创建和恢复备忘录
* @author admin
*
*/
class SaveLifeAction{
//定义一个状态,用于描述当前正在做什么..
private String state="";
//设置是否救成功
private boolean isSuccess;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
//创建一个备份的状态
public BoxMemento createMemento(){
return new BoxMemento(this.state);
}
//恢复到原来的状态
public void restoreMemento(BoxMemento boxMemento){
this.setState(boxMemento.getState());
}
}
/**
* 该类是备忘录类
* 相当于故事中的月光宝盒,他带你回到上一个状态。
* 内部实现的原理就是,保存上一状态而已。
* @author admin
*
*/
class BoxMemento{
private String state="";
public BoxMemento(String state) {
this.state = state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
/**
* 备忘录的管理者,
* 谁拿到月光宝盒,谁就可以操纵月光宝盒,
* 就可以回到过去。
* @author admin
*
*/
class BoxManager{
private BoxMemento boxMemento;
public BoxMemento getBoxMemento() {
return boxMemento;
}
public void setBoxMemento(BoxMemento boxMemento) {
this.boxMemento = boxMemento;
}
}
~~~
**备忘录模式的使用场景**
---|需要保存和恢复数据的相关状态场景。
---|提供一个可回滚(rollback)的操作,比如word中Ctrl+Z的组合键。
---|需要监控的副本场景中。
---|数据库连接的事务管理就是用的备忘录模式。
## 备忘录的扩展
---|1、实现java类中的Cloneable实现备忘录模式
使用clone方式的备忘录模式,可以使用在比较简单的场景或者比较单一的场景中,
尽量不要与其他的对象产生严重的耦合关系。
~~~
public class MementoExpand {
public static void main(String[] args) {
//定义一个发起人
OriginClass origin = new OriginClass();
origin.setState("我的原始状态");
//创建备份
origin.createOrigin();
origin.setState("我的现在状态..");
System.out.println(origin.getState());
System.out.println("------我不喜欢现在的状态-------");
//恢复原来的状态
origin.restoreOrigin();
System.out.println(origin.getState());
}
}
/**
* 发起者实现Cloneable接口,完成自身的备忘录设置。
* 无需接触其他类来保存自身的当前状态。
* @author admin
*
*/
class OriginClass implements Cloneable{
private String state;
//自身的备忘录角色
private OriginClass backUp;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
//创建备份
public void createOrigin(){
this.backUp = (OriginClass) this.clone();
}
//恢复原来的信息
public void restoreOrigin(){
this.setState(backUp.getState());
}
@Override
protected Object clone() {
try {
return (OriginClass) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
~~~
---|2多状态的备忘录模式
~~~
/**
* 通过java.beans.Introspector类获取其他类中的属性和方法
* @author admin
*
*/
public class BeanUtil {
public static void main(String[] args) {
//创建一个发起者
MyOringin origin = new MyOringin("lzl",10000,"程序员");
System.out.println("在百度公司里:"+origin.toString());
//在百度公司创建备份
MyMementor mementor = origin.createMemento();
System.out.println("感觉太累了,跳槽的阿里巴巴...");
origin.setName("lzl");
origin.setPosition("程序员");
origin.setSalary(12000);
System.out.println("跳槽到阿里:"+origin.toString());
System.out.println("----------------在这里更累,跟着老大,10天没合眼...想回到百度了.");
origin.restoreMemento(mementor);
System.out.println("回到百度,还是很轻松的。。"+origin.toString());
}
//获取发起者类中的属性参数,并保存在hashMap中
public static HashMap<String, Object> backUpProp(Object bean){
HashMap<String, Object> result = new HashMap<String, Object>();
//获得Bean描述
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
//返回PropertyDescriptor类型的javaBean描述
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
//遍历返回的javaBean
for(PropertyDescriptor des : descriptors){
String fieldName = des.getName();
//读取属性的方法
Method getter = des.getReadMethod();
//读取属性值
Object fieldValue = getter.invoke(bean, new Object[]{});
if(!fieldName.equalsIgnoreCase("class")){
result.put(fieldName, fieldValue);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
//把HashMap中的值设置到bean中。
public static void restoreProp(Object bean,HashMap<String, Object> propMap){
//获取BeanInfo
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
//获取PropertyDescriptor的对象数组
PropertyDescriptor[] descripors = beanInfo.getPropertyDescriptors();
//增强for循环,遍历所有的属性,设置到bean中
for(PropertyDescriptor des : descripors){
//获取key值对象
String fieldName = des.getName();
//如果包含这个属性
if(propMap.containsKey(fieldName)){
//获取属性set的方法
Method setter = des.getWriteMethod();
setter.invoke(bean, new Object[]{propMap.get(fieldName)});
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 类的发起者,模拟拥有多个属性。
* @author admin
*
*/
class MyOringin{
//姓名
private String name;
//薪水
private double salary;
//职位
private String position;
public MyOringin(String name,double salary,String position) {
this.name = name;
this.salary = salary;
this.position = position;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
//创建一个备份
public MyMementor createMemento(){
//将方法属性存储到BeanUtil.backUpProp()中的hashMap中
return new MyMementor(BeanUtil.backUpProp(this));
}
public void restoreMemento(MyMementor memento){
BeanUtil.restoreProp(this, memento.getBeanMap());
}
@Override
public String toString() {
return "姓名:"+this.name+"\t职位:"+this.position
+"\t薪水:"+this.salary+"\t";
}
}
/**
* 备忘录类,用于保存原有的状态。
* @author admin
*/
class MyMementor{
//定义一个hashMap来接收发起者的所有属性状态备份
private HashMap<String, Object> beanMap = new HashMap<String, Object>();
public MyMementor(HashMap<String, Object> beanMap) {
this.beanMap = beanMap;
}
public HashMap<String, Object> getBeanMap() {
return this.beanMap;
}
public void setBeanMap(HashMap<String, Object> beanMap) {
this.beanMap = beanMap;
}
}
~~~