詳解Java設計形式之備忘錄形式的應用。本站提示廣大學習愛好者:(詳解Java設計形式之備忘錄形式的應用)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解Java設計形式之備忘錄形式的應用正文
界說與構造
備忘錄(Memento)形式又稱標志(Token)形式。GOF給備忘錄形式的界說為:在不損壞封裝性的條件下,捕捉一個對象的外部狀況,並在該對象以外保留這個狀況。如許今後便可將該對象恢復到本來保留的狀況。
在講敕令形式的時刻,我們已經提到應用中央的敕令腳色可以完成undo、redo的功效。從界說可以看出備忘錄形式是專門來寄存對象汗青狀況的,這關於很好的完成undo、redo功效有很年夜的贊助。所以在敕令形式中undo、redo功效可以合營備忘錄形式來完成。
其實單就完成保留一個對象在某一時辰的狀況的功效,照樣很簡略的——將對象中要保留的屬性放到一個專門治理備份的對象中,須要的時刻則挪用商定好的辦法將備份的屬性放回到本來的對象中去。然則你要好悅目看為了能讓你的備份對象拜訪到原對象中的屬性,能否意味著你就要全體地下或許包內地下對象本來公有的屬性呢?假如你的做法曾經損壞了封裝,那末就要斟酌重構一下了。
備忘錄形式只是GOF對“恢復對象某時的原有狀況”這一成績提出的通用計劃。是以在若何堅持封裝性上——因為遭到說話特征等身分的影響,備忘錄形式並沒有具體描寫,只是基於C++論述了思緒。
1) 備忘錄(Memento)腳色:備忘錄腳色存儲“備忘提議腳色”的外部狀況。“備忘提議腳色”依據須要決議備忘錄腳色存儲“備忘提議腳色”的哪些外部狀況。為了避免“備忘提議腳色”之外的其他對象拜訪備忘錄。備忘錄現實上有兩個接口,“備忘錄治理者腳色”只能看到備忘錄供給的窄接口——關於備忘錄腳色中寄存的屬性是弗成見的。“備忘提議腳色”則可以或許看到一個寬接口——可以或許獲得本身放入備忘錄腳色中屬性。
2) 備忘提議(Originator)腳色:“備忘提議腳色”創立一個備忘錄,用以記載以後時辰它的外部狀況。在須要時應用備忘錄恢復外部狀況。
3) 備忘錄治理者(Caretaker)腳色:擔任保留好備忘錄。不克不及對備忘錄的內容停止操作或檢討。
備忘錄形式的類圖真是再簡略不外了:
通用代碼完成
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 restoreMemento(Memento memento){ this.setState(memento.getState()); } } 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; } } class Caretaker { private 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.setState("狀況1"); System.out.println("初始狀況:"+originator.getState()); Caretaker caretaker = new Caretaker(); caretaker.setMemento(originator.createMemento()); originator.setState("狀況2"); System.out.println("轉變後狀況:"+originator.getState()); originator.restoreMemento(caretaker.getMemento()); System.out.println("恢復後狀況:"+originator.getState()); } }
代碼演示了一個單狀況單備份的例子,邏輯異常簡略:Originator類中的state變量須要備份,以便在須要的時刻恢復;Memento類中,也有一個state變量,用來存儲Originator類中state變量的暫時狀況;而Caretaker類就是用來治理備忘錄類的,用來向備忘錄對象中寫入狀況或許取回狀況。
多狀況多備份備忘錄
通用代碼演示的例子中,Originator類只要一個state變量須要備份,而平日情形下,提議人腳色平日是一個javaBean,對象中須要備份的變量不止一個,須要備份的狀況也不止一個,這就是多狀況多備份備忘錄。完成備忘錄的辦法許多,備忘錄形式有許多變形和處置方法,像通用代碼那樣的方法普通不會用到,多半情形下的備忘錄形式,是多狀況多備份的。其實完成多狀況多備份也很簡略,最經常使用的辦法是,我們在Memento中增長一個Map容器來存儲一切的狀況,在Caretaker類中異樣應用一個Map容器才存儲一切的備份。上面我們給出一個多狀況多備份的例子:
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 void restoreMemento(Memento memento){ BeanUtils.restoreProp(this, memento.getStateMap()); } public String toString(){ return "state1="+state1+"state2="+state2+"state3="+state3; } } 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; } } 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 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; } public static void restoreProp(Object bean, Map<String, Object> propMap){ try { 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) { e.printStackTrace(); } } } class Caretaker { private Map<String, Memento> memMap = new HashMap<String, Memento>(); public Memento getMemento(String index){ return memMap.get(index); } public void setMemento(String index, Memento memento){ this.memMap.put(index, memento); } } class Client { public static void main(String[] args){ Originator ori = new Originator(); Caretaker caretaker = new Caretaker(); ori.setState1("中國"); ori.setState2("強大"); ori.setState3("繁華"); System.out.println("===初始化狀況===\n"+ori); caretaker.setMemento("001",ori.createMemento()); ori.setState1("軟件"); ori.setState2("架構"); ori.setState3("優良"); System.out.println("===修正後狀況===\n"+ori); ori.restoreMemento(caretaker.getMemento("001")); System.out.println("===恢復後狀況===\n"+ori); } }
備忘錄形式的優缺陷和實用場景
備忘錄形式的長處有:
當提議人腳色中的狀況轉變時,有能夠這是個毛病的轉變,我們應用備忘錄形式便可以把這個毛病的轉變復原。
備份的狀況是保留在提議人腳色以外的,如許,提議人腳色就不須要對各個備份的狀況停止治理。
備忘錄形式的缺陷:
在現實運用中,備忘錄形式都是多狀況和多備份的,提議人腳色的狀況須要存儲到備忘錄對象中,對資本的消費是比擬嚴重的。
假如有須要供給回滾操作的需求,應用備忘錄形式異常合適,好比jdbc的事務操作,文本編纂器的Ctrl+Z恢復等。