国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > Java > 正文

詳解Java設(shè)計(jì)模式之備忘錄模式的使用

2019-11-26 14:33:42
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

定義與結(jié)構(gòu)    

備忘錄(Memento)模式又稱(chēng)標(biāo)記(Token)模式。GOF給備忘錄模式的定義為:在不破壞封裝性的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)。這樣以后就可將該對(duì)象恢復(fù)到原先保存的狀態(tài)。

  在講命令模式的時(shí)候,我們?cè)?jīng)提到利用中間的命令角色可以實(shí)現(xiàn)undo、redo的功能。從定義可以看出備忘錄模式是專(zhuān)門(mén)來(lái)存放對(duì)象歷史狀態(tài)的,這對(duì)于很好的實(shí)現(xiàn)undo、redo功能有很大的幫助。所以在命令模式中undo、redo功能可以配合備忘錄模式來(lái)實(shí)現(xiàn)。

  其實(shí)單就實(shí)現(xiàn)保存一個(gè)對(duì)象在某一時(shí)刻的狀態(tài)的功能,還是很簡(jiǎn)單的――將對(duì)象中要保存的屬性放到一個(gè)專(zhuān)門(mén)管理備份的對(duì)象中,需要的時(shí)候則調(diào)用約定好的方法將備份的屬性放回到原來(lái)的對(duì)象中去。但是你要好好看看為了能讓你的備份對(duì)象訪問(wèn)到原對(duì)象中的屬性,是否意味著你就要全部公開(kāi)或者包內(nèi)公開(kāi)對(duì)象原本私有的屬性呢?如果你的做法已經(jīng)破壞了封裝,那么就要考慮重構(gòu)一下了。

  備忘錄模式只是GOF對(duì)“恢復(fù)對(duì)象某時(shí)的原有狀態(tài)”這一問(wèn)題提出的通用方案。因此在如何保持封裝性上――由于受到語(yǔ)言特性等因素的影響,備忘錄模式并沒(méi)有詳細(xì)描述,只是基于C++闡述了思路。


  1) 備忘錄(Memento)角色:備忘錄角色存儲(chǔ)“備忘發(fā)起角色”的內(nèi)部狀態(tài)?!皞渫l(fā)起角色”根據(jù)需要決定備忘錄角色存儲(chǔ)“備忘發(fā)起角色”的哪些內(nèi)部狀態(tài)。為了防止“備忘發(fā)起角色”以外的其他對(duì)象訪問(wèn)備忘錄。備忘錄實(shí)際上有兩個(gè)接口,“備忘錄管理者角色”只能看到備忘錄提供的窄接口――對(duì)于備忘錄角色中存放的屬性是不可見(jiàn)的。“備忘發(fā)起角色”則能夠看到一個(gè)寬接口――能夠得到自己放入備忘錄角色中屬性。

  2) 備忘發(fā)起(Originator)角色:“備忘發(fā)起角色”創(chuàng)建一個(gè)備忘錄,用以記錄當(dāng)前時(shí)刻它的內(nèi)部狀態(tài)。在需要時(shí)使用備忘錄恢復(fù)內(nèi)部狀態(tài)。

  3) 備忘錄管理者(Caretaker)角色:負(fù)責(zé)保存好備忘錄。不能對(duì)備忘錄的內(nèi)容進(jìn)行操作或檢查。

  備忘錄模式的類(lèi)圖真是再簡(jiǎn)單不過(guò)了:

2016217112919585.jpg (518×47)

通用代碼實(shí)現(xiàn)

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("狀態(tài)1");     System.out.println("初始狀態(tài):"+originator.getState());     Caretaker caretaker = new Caretaker();     caretaker.setMemento(originator.createMemento());     originator.setState("狀態(tài)2");     System.out.println("改變后狀態(tài):"+originator.getState());     originator.restoreMemento(caretaker.getMemento());     System.out.println("恢復(fù)后狀態(tài):"+originator.getState());   } } 

        代碼演示了一個(gè)單狀態(tài)單備份的例子,邏輯非常簡(jiǎn)單:Originator類(lèi)中的state變量需要備份,以便在需要的時(shí)候恢復(fù);Memento類(lèi)中,也有一個(gè)state變量,用來(lái)存儲(chǔ)Originator類(lèi)中state變量的臨時(shí)狀態(tài);而Caretaker類(lèi)就是用來(lái)管理備忘錄類(lèi)的,用來(lái)向備忘錄對(duì)象中寫(xiě)入狀態(tài)或者取回狀態(tài)。

多狀態(tài)多備份備忘錄
       通用代碼演示的例子中,Originator類(lèi)只有一個(gè)state變量需要備份,而通常情況下,發(fā)起人角色通常是一個(gè)javaBean,對(duì)象中需要備份的變量不止一個(gè),需要備份的狀態(tài)也不止一個(gè),這就是多狀態(tài)多備份備忘錄。實(shí)現(xiàn)備忘錄的方法很多,備忘錄模式有很多變形和處理方式,像通用代碼那樣的方式一般不會(huì)用到,多數(shù)情況下的備忘錄模式,是多狀態(tài)多備份的。其實(shí)實(shí)現(xiàn)多狀態(tài)多備份也很簡(jiǎn)單,最常用的方法是,我們?cè)贛emento中增加一個(gè)Map容器來(lái)存儲(chǔ)所有的狀態(tài),在Caretaker類(lèi)中同樣使用一個(gè)Map容器才存儲(chǔ)所有的備份。下面我們給出一個(gè)多狀態(tài)多備份的例子:

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("中國(guó)");     ori.setState2("強(qiáng)盛");     ori.setState3("繁榮");     System.out.println("===初始化狀態(tài)===/n"+ori);          caretaker.setMemento("001",ori.createMemento());     ori.setState1("軟件");     ori.setState2("架構(gòu)");     ori.setState3("優(yōu)秀");     System.out.println("===修改后狀態(tài)===/n"+ori);          ori.restoreMemento(caretaker.getMemento("001"));     System.out.println("===恢復(fù)后狀態(tài)===/n"+ori);   } } 

備忘錄模式的優(yōu)缺點(diǎn)和適用場(chǎng)景
備忘錄模式的優(yōu)點(diǎn)有:
當(dāng)發(fā)起人角色中的狀態(tài)改變時(shí),有可能這是個(gè)錯(cuò)誤的改變,我們使用備忘錄模式就可以把這個(gè)錯(cuò)誤的改變還原。
備份的狀態(tài)是保存在發(fā)起人角色之外的,這樣,發(fā)起人角色就不需要對(duì)各個(gè)備份的狀態(tài)進(jìn)行管理。
備忘錄模式的缺點(diǎn):
在實(shí)際應(yīng)用中,備忘錄模式都是多狀態(tài)和多備份的,發(fā)起人角色的狀態(tài)需要存儲(chǔ)到備忘錄對(duì)象中,對(duì)資源的消耗是比較嚴(yán)重的。
如果有需要提供回滾操作的需求,使用備忘錄模式非常適合,比如jdbc的事務(wù)操作,文本編輯器的Ctrl+Z恢復(fù)等。

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 农安县| 鹤峰县| 留坝县| 甘谷县| 塔河县| 老河口市| 延津县| 清涧县| 嘉善县| 蒲城县| 旌德县| 儋州市| 合阳县| 且末县| 全椒县| 邹城市| 新和县| 涟水县| 乌海市| 肃宁县| 桓仁| 六枝特区| 西充县| 烟台市| 家居| 商水县| 松原市| 灵武市| 新野县| 通辽市| 广宁县| 汪清县| 民县| 巴里| 三都| 凤凰县| 花垣县| 肇州县| 涞水县| 鲁甸县| 新郑市|