在需要中间值的时候此时需要使用备忘录模式

类图

代码

public class Boy {
    // 男孩的状态
    private String state = "";
    // 认识女孩后状态改变。
    public void changeState(){
       this.state = "心情不好";
    }
    public String getState(){
        return state;
    }
    public void setState(String state){
        this.state = state;
    }
}

最后书写场景类

public class Client {
    public static void main(String [] args){
        // 声明出主角
        Boy boy = new Boy();
        // 初始化状态
        boy.setState("心情很棒!");
        System.out.println(boy.getState());
        // 需要记录下当前的状态,backup用来记录当前的状态。
        Boy backup = new Boy();
        // 保存当前状态
        backup.setState(boy.getState());
        // 追女孩的时候,状态改变
        boy.changeState();
        System.out.println(boy.getState());
        // 失败,恢复原状
        boy.setState(backup.getState());
    }
}

反思

此时场景类,为高层模块,或非近亲模块的调用者,此时backup变量为多余的。此时破坏了封装。

此时类比平常使用的备忘录方式,新建一个备忘录,然后保存当前的状态。

改进

类图

public class Boy{
    // 进行状态的保留
    private String state = "";
    // 心情改变
    public void changeState(){
        this.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());
    }
}
// 备忘录
public class Memento{
    // 状态
    private String state = "";
    // 通过构造函数注入
    public Memento(String _state){
        this.state = _state;
    }
    public String getState(){
        return state;
    }
    public void setState(String state){
        this.state = state;
    }
}

最后场景类

public class Client {
    public static void main(String[] args){
        // 声明主角
        Boy boy = new Boy();
        // 初始化当前状态
        boy.setState("心情很棒!");
        // 使用备忘录,记录当前状态
        Memento men = boy.createMemento();
        // 状态改变
        boy.changeState();
        // 失败,恢复原状,通过备忘录的方式恢复原状
        boy.restoreMemento(mem);
    }
}

继续更改

对于迪米特法则来说,只和朋友类通信,备忘录对象不是朋友类,那么可以创建备份点,需要恢复的时候,直接恢复当前的状态即可。

// 备忘录管理者
public class Caretaker{
    // 备忘录对象
    private Memento memento;
    public Memento getMemento(){
        return memento;
    }
    public void setMemento(Memento memento){
        this.memento = memento;
    }
}

上方是一个最简单javaBean 即,可重用的组件
改进后的场景类如下

public class Client {
    public static void main(String[] args){
        // 声明主角
        Boy boy = new Boy();
        // 声明出备忘录管理者
        Caretaker caretaker = new Caretaker();
        // 初始化当前状态
        boy.setState("good!");
        // 记录当前状态
        caretaker.setMemento(boy.createMemento());
        // 状态改变
        boy.changeState();
        // 恢复原先状态
        boy.restoreMemento(caretaker.getMemento());
    }
}

应用

需要保存恢复数据的当前状态的场景
提供一个可回滚的操作,例如ctrl + z
数据库的事物,使用备忘录模式,因为当一个事物执行失败的时候,进行回滚。
生命周期,使用的时候需要,不使用的时候直接删除
性能,不要重复的建立,恢复,否则会影响系统性能。

和原型模式结合使用

原型模式,通过原型,快速的复制出多个对象。即通过复制的方式,产生对象的一个内部状态。
将备忘录管理和当前状态融合在一起的类。

public interface Cloneable {
    protected Originator clone();
}
public class Originator implements Cloneable {
   // 内部状态
   private String state = "";
   // 获取一个state
   public String getState(){
       return state;
   }
   // 设置一个state
   public void setState(String state){
       this.state = state;
   }
    // 创建一个备忘录
    public Originator createMemento(){
        return this.clone();
    }
    // 恢复一个备忘录
    public void restoreMemento(Originator _originator){
        this.setState(_originator.getState());
    }
    // 克隆当前对象
    @Override 
    protected Originator clone(){
        try{
            return (Originator)super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
    }
}

在设置备忘录管理员

public class Caretaker {
    // 发起人对象
    private Originator originator;
    public Originator getOriginator(){
        return originator;
    }
    public void setOriginator(Originator originator){
        this.originator = originator;
    }
}

上方为一个java bean

最后发起了自主备份和恢复
此时依旧可以继续更改,进行合并

public class Originator implements Cloneable {
    private Originator backup;
    // 内部状态
    private String state = "";
    public String getState(){
        return state;
    }
    public void setState(String state){
        this.state = state;
    }
    // 创建一个备忘录
    public void createMemento(){
        this.backup = this.clone();
    }
    // 恢复一个备忘录
    public void restoreMemento(){
        // 需要断言
        this.setState(this.backup.getState());
    }
    // 克隆对象
    @Override
    protected Originator clone(){
        try{
            return (Originator)super.clone;
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return null;
    }
}

使用了一个类,同时管理当前状态,以及当前的备忘录

最后场景类

public class Client {
    public static void main(String[] args){
        // 定义发起人
        Originator originator = new Originator();
        // 建立初始状态
        originator.setState("初始状态");
        // 建立备份
        originator.createMemento();
        // 修改状态
        originator.setState("修改状态");
        // 恢复原有状态
        originator.restoreMemento();
    }
}

多状态的备忘录模式

// 发起人角色
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 Memento createMemento(){
        Beanutils.restoreProp(this,_mementi.getStateMap());
    }
}

BeanUtils工具类

public class BeanUtils {
    // bean属性放入hashmap
    public static HashMap<String, Object>backupProp(Object bean){
        HashMap<String, Object> result = new HashMap<String, Object>();
        try{
            // 获得Bean描述,通过内省机制,获取。获取的是一个Beaninfo
            Beaninfo beaninfo = introspector.getBeaninfo(bean.getClass());
            // 获得属性描述,使用getPropertyDescriptors方法获取当前的属性的描述符
            PropertyDescriptor[] descriptors = beaninfo.getPropertyDescriptors();
            // 利用循环取出描述
            for(PropertyDescriptor des:descriptors){
                // 属性名称
                String fieldName = des.getName();
                // 设置一个读取属性的方法,其中getReadMethod返回一个类型为Method类型的方法。
                Method getter = des.getReadMethod();
                // 读取属性值, invoke 调用包装在在内的bean对象的new Object参数的方法,返回值为getter。上方获得了一个读该属性的方法,然后调用该方法invoke方法,将bean对象包装进入,调用参数为空的数组获取返回的对象。
                Object fieldValue = getter.invoke(bean, new Object[]{});
                if(!fieldName.equalslgnoreCase("class")){
                    result.put(fieldName, fieldValue);
                }catch(Exception e){
                    // 异常处理
                }
                return result;
            }
            
        }
    }
    // 把HashMap值放回bean中
    public static void restoreProp(OBject bean, HashMap<String, Object> propMap){
        try{
            // 获得Bean描述
            Beaninfo beaninfo = intospector.getBeaninfo(bean.getClass());
            // 获得属性描述
            PropertyDescriptor[] descriptors = beaninfo.getPropertyDescriptors();
            // 遍历所有的属性
            for(PropertyDescriptor des:descriptors){
                // 属性名称
                String fieldName = des.getName();
                // 如果有这个属性
                if(propMap.containsKey(fieldName)){
                    // 写属性的方法
                    Method setter = des.getWriteMethod();
                    seeter.invoke(bean, new Object[]{propMap.get(fieldName)});
                    
                }
            }
        }catch(Exception e){
            // 异常处理
            e.printStackTrace();
        }
    }
}

备忘录角色

public class Memento {
    // 接受HashMap作为状态
    private HashMap<String, Object> stateMap;
    // 接受一个对象,建立备份
    public Memento(HashMap<String, Object> map){
        this.stateMap = map;
    }
    public HashMap<String, Object> getStateMap(){
        return stateMap;
    }
    public void setStateMap(HashMap<String, Object>stateMap){
        this.stateMap = stateMap;
    }
}

编写场景类

public class Client{
    public static void main(String[] args){
        // 定义发起人
        Originator ori = new Originator();
        // 定义管理员
        Caretaker caretaker = new Caretaker();
        // 初始化
        ori.setState1("1");
        ori.setState2("2");
        ori.setState3("3");
        // 创建备忘录
        caretaker.setMemento(ori.createMemento());
        // 修改状态值
        ori.setState1("4");
        ori.setState2("5");
        ori.setState3("6");
        // 恢复备忘录
        ori.restoreMemento(caretaker.getMemento());
    }
}

多备份的备忘录

定义备忘录管理员

public class Caretaker {
    // 容纳备忘录的容器
    private HashMap<String ,Memento> memMap = new HashMap<String, Memento>();
    public Memento getMemento(String idx){
        return menMap.get(idx);
    }
    public void setMemento(String idx, Memento memento){
        this.memMap.put(idx, memento);
    }
}

定义场景类

public class Client{
    public static void main(String[] args){
        // 定义发起人
        Originator originator = new Originator();
        // 定义备忘录管理员
        Caretaker caretaker = new Caretaker();
        // 创建备忘录
        caretaker.setMemento("001", originator.createMemento());
        caretaker.setMemento("002", originator.createMemento());
        // 恢复指定标记的备忘录
        originator.restoreMemento(caretaker.getMemento("001"));
    }
}

ps: 会有内存溢出问题

对封装更改权限

可以使用内部类的方式进行权限的限制

// 定义发起人
public class Originator {
    // 内部状态
    private String state = "";
    public String getState(){
        return state;
    }
    public void setState(String state){
        this.state = state;
    }
    // 创建备忘录
    public IMemento createMemento(){
        return new Memento(this.state);
    }
    // 恢复备忘录
    public void restoreMemento(IMemento _memento){
        this.setState((Memento)_memento.getState());
    }
    // 内置类
    private class Memento implements IMemento{
        // 发起人内部状态
        private String state = "";
        // 构造函数注入
        private Memento(String _state){
            this.state = _state;
        }
        private String getState(){
            return state;
        }
        private void setState(String state){
            this.state = state;
        }
    }
}

在上方中内置的Memento是private访问权限只有自己能访问。
若要产生关联关系,通过接口

public interface IMemento{

}
// 备忘录管理者
public class Caretaker {
    // 备忘录对象
    // 定义一个接口
    private IMemento memento;
    public IMemento getMemento(){
        return memento;
    }
    public void setMemento(IMemento memento){
        this.memento = memento;
    }
}

总结

使用备忘录模式,直接定义一个类,进行备忘即可。
用途,用于恢复某个节点。