/* All Contributors (C) 2020 */
package cn.edu.jxnu.examples.design;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;

/**
 * Copyright © 2018 梦境迷离. All rights reserved.
 *
 * @description:备忘录：定义：在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。 @Package:
 *     cn.jxnu.edu.designpattern
 * @author: 梦境迷离
 * @date: 2018年3月20日 上午11:00:04
 */

/**
 * ● Originator发起人角色 记录当前时刻的内部状态，负责定义哪些属于备份范围的状态，负责创建和恢复备忘录数据。 ● Memento备忘录角色（简单的javabean）
 * 负责存储Originator发起人对象的内部状态，在需要的时候提供发起人需要的内部状态。 ● Caretaker备忘录管理员角色（简单的javabean） 对备忘录进行管理、保存和提供备忘录。
 * 使用场景： ● 需要保存和恢复数据的相关状态场景。 ● 提供一个可回滚（rollback）的操作。 ● 需要监控的副本场景中。 ● 数据库连接的事务管理就是用的备忘录模式。 注意：
 * ●备忘录的生命期 ●备忘录的性能 不要在频繁建立备份的场景中使用备忘录模式（比如一个for循环中）。 clone方式备忘录： ● 发起人角色融合了发起人角色和备忘录角色，具有双重功效
 * 多状态的备忘录模式 ● 增加了一个Memento类，其中backupProp是把发起人的所有属性值转换到HashMap中，方便备忘录角色存储。
 * restoreProp方法则是把HashMap中的值返回到发起人角色中。
 */
public class Memento {
    // 把bean的所有属性及数值放入到Hashmap中
    public static HashMap<String, Object> backupProp(Object bean) {
        HashMap<String, Object> result = new HashMap<String, Object>();
        try {
            // 获得Bean描述
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            // 获得属性描述
            PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
            // 遍历所有属性
            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) {
            // 异常处理
        }
        return result;
    }

    // 把HashMap的值返回到bean中
    public static void restoreProp(Object bean, HashMap<String, Object> propMap) {
        try {
            // 获得Bean描述
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            // 获得属性描述
            PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
            // 遍历所有属性
            for (PropertyDescriptor des : descriptors) {
                // 属性名称
                String fieldName = des.getName();
                // 如果有这个属性
                if (propMap.containsKey(fieldName)) {
                    // 写属性的方法
                    Method setter = des.getWriteMethod();
                    setter.invoke(bean, new Object[] {propMap.get(fieldName)});
                }
            }
        } catch (Exception e) {
            // 异常处理
            System.out.println("shit");
            e.printStackTrace();
        }
    }
}
