一天一種設計模式之二-----備忘錄模式

一.備忘錄模式

  1. 備忘錄模式屬於三種設計模式中的行爲型模式(另外兩種是建立型模式和結構型模式)。java

  2. 定義:在不破壞封閉性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態。這樣之後就能夠將改變了的對象恢復到原先保存的狀態。設計模式

  3. 之因此須要存儲改變前的對象,是由於java對象的傳遞是引用傳遞。A a1=a,a裏面的東西變就等同於a1裏面的東西變。
    架構

  4. 備忘錄模式的結構:ide

    1. 發起人:負責記錄當前時刻的內部狀態,負責定義那些屬於備忘範圍的狀態,負責建立和恢復備忘錄數據。測試

    2. 備忘錄:負責存儲發起人對象的內部狀態,在須要的時候提供發起人須要的內部狀態。this

    3. 管理角色:對備忘錄進行管理,保存和提供備忘錄。spa

  5. 優勢:設計

    1. 當發起人角色中的狀態改變時,有可能這是個錯誤的改變,咱們使用備忘錄模式就能夠還原。rest

    2. 備份的狀態是保存在發起人角色以外的,這樣,發起人角色就不須要對哥哥備份狀態進行管理。代碼規範

    3. 若是有須要提供回滾操做的需求,使用備忘錄模式很是合適

  6. 缺點:

    1. 在實際應用中,備忘錄模式多事多狀態和多備份的,發起人角色的狀態須要存儲到備忘錄對象中,對字段的小號是比較嚴重的。

  7. 從設計模式角度講:我的感受他對六大設計模式原則的體現不是很大,只能說知足單一職責原則把,好比一個類的實例若是想要從不能備忘改成須要備忘,經過該模式,咱們仍是要爲該類增長一個保存和恢復的方法,違背了開閉原則,client端調用的時候須要知道。爲何不直接定義一個容器,拷貝一個該對象,須要回覆的時候再賦值過去呢(這樣貌似又不三不四了,由於體現不出來備忘是某個對象的能力,略糾結啊)。(歡迎大神透徹分析下)

二.測試代碼


  1. 簡單版測試用例:

public class BeiwangluTest {
    public static void main(String[] args) {
        Originator originator=new Originator();
        originator.setState("狀態1");
        Caretaker caretaker=new Caretaker();
        caretaker.setMemento(originator.createMemento());
        originator.setState("狀態2");
        originator.restorMemento(caretaker.getMemento());
        System.out.println(originator.getState());;//這是以前的狀態
        originator.createMemento();//這是以前的memento
    }
}
/**
 * 發起ren 
 * @author 58
 *
 */
class Originator{
    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 restorMemento(Memento memento){
        this.setState(memento.getState());
    }
    
}
/**
 * 備忘錄
 * @author 58
 *
 */
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;
    }
}

/**
 * 管理角色
 * @author 58
 *
 */
class Caretaker{
    private Memento memento;

    public Memento getMemento() {
        return memento;
    }
    
    public void setMemento(Memento memento) {
        this.memento = memento;
    }
    
    
}

    上述代碼只作到恢復了一個狀態,通常狀況下咱們須要恢復的是一個複雜的對象。

    最經常使用的方法是在memento中增長一個map容器來存儲全部的狀態,在caretaker類中一樣適用一個map容器存儲全部備份。下面代碼以下(應該也能夠經過深拷貝實現,經過beanutils來實現會更更簡單,有時間的話試試)

        (話外代碼規範:寫代碼時名字要起好,在方法中list list=xxx這種就很差,應該表示清楚list是幹嗎的,否則看起來很費勁。簡單命名應該只出如今循環遍歷中,trycatch等代碼常常會給咱們生成一個//TODO註釋,這個註釋不要留,會讓有代碼潔癖的人反感,能夠從eclipese設置裏去掉,要是不知道爲何,本身去百度//TODO,//XXX,//FIXME 這些註釋各自都是幹嗎用的,嚴格要求從我作起)

public class BeiwangluTest {
    public static void main(String[] args) {
        Originator ori=new Originator();
        Caretaker caretaker=new Caretaker();
        ori.setState1("中國");
        ori.setState2("強盛");
        ori.setState3("繁榮");
        System.out.println("狀態1"+ori);
        
        caretaker.setMemento("001",ori.createMemento());
        ori.setState1("軟件");
        ori.setState2("架構");
        ori.setState3("優秀");
        System.out.println("狀態2"+ori);
        
        ori.restorMemento(caretaker.getMemento("001"));
        
        System.out.println("回覆後的狀態"+ori);
    }
}

/**
 * 發起人
 * 
 * @author 58
 *
 */
class Originator {
    private String state1 = "";
    private String state2 = "";
    private String state3 = "";

    public Memento createMemento() {
        return new Memento(BeanUtils.backupProp(this));
    }

    public void restorMemento(Memento memento) {
        BeanUtils.restoreProp(this, memento.getStateMap());
    }

    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;
    }

    @Override
    public String toString() {
        return "Originator [state1=" + state1 + ", state2=" + state2
                + ", state3=" + state3 + "]";
    }

    
}

/**
 * 備忘錄
 * 
 * @author 58
 *
 */
class Memento {
    private Map<String, Object> stateMap;

    public Memento(Map<String, Object> map) {
        this.stateMap = map;
    }

    public Map<String, Object> getStateMap() {
        return stateMap;
    }

    public void setStateMap(Map<String, Object> stateMap) {
        this.stateMap = stateMap;
    }

}

/**
 * 管理角色
 * 
 * @author 58
 *
 */
class Caretaker {
    private Map<String, Memento> meMap = new HashMap<String, Memento>();

    public Memento getMemento(String index) {
        return meMap.get(index);
    }

    public void setMemento(String index, Memento memento) {
        this.meMap.put(index, memento);
    }

    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }

}

class BeanUtils {
    public static Map<String, Object> backupProp(Object bean) {
        Map<String, Object> result = new HashMap<String, Object>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] descriptors = beanInfo
                    .getPropertyDescriptors();
            for (PropertyDescriptor descriptor : descriptors) {
                String fieldName = descriptor.getName();
                Method getter = descriptor.getReadMethod();
                // TODO null和new Object[]{}是不同的,null通常是執行抽象方法。
                Object fieldValue = getter.invoke(bean, new Object[]{});
                if (!fieldName.equalsIgnoreCase("class")) {
                    result.put(fieldName, fieldValue);
                }
            }
        } catch (IntrospectionException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void restoreProp(Object bean, Map<String, Object> propMap) {
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] descriptors = beanInfo
                    .getPropertyDescriptors();
            for (PropertyDescriptor descriptor : descriptors) {
                String fieldName = descriptor.getName();
                if (propMap.containsKey(fieldName)) {
                    Method setterMethod = descriptor.getWriteMethod();
                    setterMethod.invoke(bean,
                            new Object[] { propMap.get(fieldName) });
                }
            }
        } catch (IntrospectionException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
相關文章
相關標籤/搜索