人在江湖

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            82 Posts :: 10 Stories :: 169 Comments :: 0 Trackbacks

          備忘錄(Memento Pattern)模式
          備忘錄模式又叫做快照模式(Snapshot Pattern)或Token模式,是對象的行為模式。
          備忘錄對象是一個用來存儲另外一個對象內(nèi)部狀態(tài)的快照的對象。備忘錄模式的用意是在不破壞封裝的條件下,將一個對象的狀態(tài)捕捉住,并外部化
          存儲起來,從而可以在將來合適的時候把這個對象還原到存儲起來的狀態(tài)。備忘錄模式常常與命令模式和迭代子模式一同使用。
          常見的軟件系統(tǒng)往往不止存儲一個狀態(tài),而是需要存儲多個狀態(tài)。這些狀態(tài)常常是一個對象歷史發(fā)展的不同階段的快照,存儲這些快照的備忘錄對象
          叫做此對象的歷史,某一個快照所處的位置叫做檢查點。
          備忘錄角色:
          備忘錄角色有如下的責(zé)任。
          1、將發(fā)起人(Originator)對象的內(nèi)部狀態(tài)存儲起來,備忘錄可以根據(jù)發(fā)起人對象的判斷來決定存儲多少
               發(fā)起人(Originator)對象的內(nèi)部狀態(tài)。
          2、備忘錄可以保護(hù)其內(nèi)容不被發(fā)起人對象之外的任何對象所讀取。備忘錄有兩個等效的接口:
          1、窄接口:負(fù)責(zé)人(Caretaker)對象(和其他除發(fā)起人對象之外的任何對象)看到的是備忘錄的窄
             接(narrow interface),這個窄接口只允許它把備忘錄對象傳給其他的對象;
          2、寬接口:與負(fù)責(zé)人對象看到的窄接口相反的是,發(fā)起人對象可以看到一個寬接口(wide interface),
             這個寬接口允許它讀取所有的數(shù)據(jù),以便根據(jù)數(shù)據(jù)恢復(fù)這個發(fā)起人對象的內(nèi)部狀態(tài)。853P
          發(fā)起人角色:
          發(fā)起人角色有如下責(zé)任:
          1、創(chuàng)建一個含有當(dāng)前的內(nèi)部狀態(tài)的備忘錄對象。
          2、使用備忘錄對象存儲其內(nèi)部狀態(tài)。
          負(fù)責(zé)人角色:
          負(fù)責(zé)人角色有如下的責(zé)任:
          1、負(fù)責(zé)保存?zhèn)渫泴ο?br>2、不檢查備忘錄對象的內(nèi)容。

          Java代碼

             1: 寬接口和白箱:
             2:         發(fā)起人角色
             3:         public class Originator{
             4:             private String state;
             5:             
             6:             //工廠方法,返還一個新的備忘錄對象
             7:             public Memento createMemento(){
             8:                 return new Memento(state);
             9:             }
            10:             
            11:             //將發(fā)起人恢復(fù)到備忘錄對象所記載的狀態(tài)
            12:             public void restoreMemento(Memento memento){
            13:                 this.state = memento.getState();
            14:             }
            15:             
            16:             //狀態(tài)的取值方法
            17:             public String getState(){
            18:                 return this.state;
            19:             }
            20:             
            21:             //狀態(tài)的賦值方法
            22:             public void setState(String state){
            23:                 this.state = state;
            24:                 System.out.println("Current state = " + this.state);
            25:             }
            26:         }
            27:         
            28:         備忘錄模式要求備忘錄對象提供兩個不同的接口:一個寬接口提供給發(fā)起人對象,另一個窄接口提供給所有其他的對象,包括負(fù)責(zé)人對象。
            29:         寬接口允許發(fā)起人讀取到所有的數(shù)據(jù);窄接口只允許它把備忘錄對象傳給其他的對象而看不到內(nèi)部的數(shù)據(jù)。
            30:         //備忘錄角色
            31:         public class Memento{
            32:             private String state;
            33:             
            34:             public Memento(String state){
            35:                 this.state = state;
            36:             }
            37:             
            38:             public String getState(){
            39:                 return this.state;
            40:             }
            41:             
            42:             public void setState(String state){
            43:                 this.state = state;
            44:             }
            45:         }
            46:         
            47:         負(fù)責(zé)人角色負(fù)責(zé)保存?zhèn)渫泴ο?,但是從不修改(甚至不查看)備忘錄對象的?nèi)容(一個更好的實現(xiàn)是負(fù)責(zé)人對象根本無法從備忘錄
            48:         對象中讀取個修改其內(nèi)容)
            49:         
            50:         //負(fù)責(zé)人角色
            51:         public class Caretaker{
            52:             private Memento memento;
            53:             
            54:             //備忘錄的取值方法
            55:             public Memento retrieveMemento(){
            56:                 return this.memento;
            57:             }
            58:             
            59:             //備忘錄的賦值方法
            60:             public void saveMemento(Memento memento){
            61:                 this.memento = memento;
            62:             }
            63:         }
            64:         
            65:         //客戶端
            66:         public class Client{
            67:             private static Originator o = new Originator();
            68:             private static Caretaker c= new Caretaker();
            69:             private static void main(String[] args){
            70:                 //該負(fù)責(zé)人對象的狀態(tài)
            71:                 o.setState("On");
            72:                 //創(chuàng)建備忘錄對象,并將發(fā)起人對象的狀態(tài)存儲起來
            73:                 c.saveMemento(o.createMemento());
            74:                 //修改發(fā)起人對象的狀態(tài)
            75:                 o.setState("Off");
            76:                 //恢復(fù)發(fā)起人對象的狀態(tài)
            77:                 o.restoreMemento(c.retrieveMemento());
            78:             }
            79:         }
            80:         首先將發(fā)起人對象的狀態(tài)設(shè)置成“On”(或者任何有效狀態(tài)),并且創(chuàng)建一個備忘錄對象將這個狀態(tài)存儲起來;然后將發(fā)起人對象
            81:         的狀態(tài)改成“Off”(或者任何狀態(tài));最后又將發(fā)起人對象恢復(fù)到備忘錄對象所存儲起來的狀態(tài),即“On”狀態(tài)(或者先前所
            82:         存儲的任何狀態(tài))
            83:         
            84:         備忘錄系統(tǒng)運(yùn)行的時序是這樣的:
            85:             (1)將發(fā)起人對象的狀態(tài)設(shè)置成“On”。
            86:             (2)調(diào)用發(fā)起人角色的createMemento()方法,創(chuàng)建一個備忘錄對象將這個狀態(tài)存儲起來。
            87:             (3)將備忘錄對象存儲到負(fù)責(zé)人對象中去。
            88:         備忘錄系統(tǒng)恢復(fù)的時序是這樣的:
            89:             (1)將發(fā)起人對象的狀態(tài)設(shè)置成“Off”;
            90:             (2)將備忘錄對象從負(fù)責(zé)人對象中取出;
            91:             (3)將發(fā)起人對象恢復(fù)到備忘錄對象所存儲起來的狀態(tài),“On”狀態(tài)。
            92:         
            93:         白箱實現(xiàn)的優(yōu)缺點
            94:             白箱實現(xiàn)的一個明顯的好處是比較簡單,因此常常用做教學(xué)目的。白箱實現(xiàn)的一個明顯的缺點是破壞對發(fā)起人狀態(tài)的封裝。
            95:             
            96:     窄接口或者黑箱實現(xiàn)
            97:         //發(fā)起人角色
            98:         public class Originator{
            99:             private String state;
           100:             
           101:             public Originator(){
           102:             }
           103:             
           104:             //工廠方法,返還一個新的備忘錄對象
           105:             public MementoIF createMemento(){
           106:                 return new Memento(this.state);    
           107:             }
           108:             
           109:             //將發(fā)起人恢復(fù)到備忘錄對象記錄的狀態(tài)
           110:             public void restoreMemento(MementoIF memento){
           111:                 Memento aMemento = (Memento)memento;
           112:                 this.setState(aMemento.getState());
           113:             }
           114:             
           115:             public String getState(){
           116:                 return this.state;
           117:             }
           118:             
           119:             public void setState(){
           120:                 this.state = state;
           121:                 System.out.println("state = " + state);
           122:             }
           123:             
           124:             protected class Memento implements MementoIF{
           125:                 private String savedState;
           126:                 private Mememto(String someState){
           127:                     savedState = someState;
           128:                 }
           129:                 
           130:                 private void setState(String someState){
           131:                     savedState = someState;
           132:                 }
           133:                 
           134:                 private String getState(){
           135:                     return savedState;
           136:                 }
           137:             }
           138:         }
           139:         
           140:         public interface MementoIF{}
           141:         
           142:         public class Caretaker{
           143:             private MementoIF memento;
           144:             
           145:             public MementoIF retrieveMemento(){
           146:                 return this.memento;
           147:             }
           148:             
           149:             public void saveMemento(MementoIF memento){
           150:                 this.memento = memento;
           151:             }
           152:         }
           153:         
           154:         public class Client{
           155:             private static Originator o = new Originator();
           156:             private static Caretaker c = new Caretaker();
           157:             
           158:             public static void main(String args[]){
           159:                 //改變負(fù)責(zé)人對象的狀態(tài)
           160:                 o.setState("On");
           161:                 //創(chuàng)建備忘錄對象,并將發(fā)起人對象的狀態(tài)存儲起來
           162:                 c.saveMemento(o.createMemento());
           163:                 //修改發(fā)起人對象的狀態(tài)
           164:                 o.setState("Off");
           165:                 //恢復(fù)發(fā)起人對象的狀態(tài)
           166:                 o.restoreMemento(c.retrieveMemento());
           167:             }
           168:         }
           169:         
           170:         黑箱實現(xiàn)運(yùn)行時的時序為;
           171:             (1)將發(fā)起人對象的狀態(tài)設(shè)置成“On”。
           172:             (2)調(diào)用發(fā)起人角色的 createMemento()方法,創(chuàng)建一個備忘錄對象將這個狀態(tài)存儲起來。
           173:             (3)將備忘錄對象存儲到負(fù)責(zé)人對象中去。由于負(fù)責(zé)人對象拿到的僅是 MementoIF類型,因此無法讀出備忘錄內(nèi)部的狀態(tài)。
           174:         恢復(fù)時的時序為:
           175:             (1)將發(fā)起人對象的狀態(tài)設(shè)置成“Off”;
           176:             (2)將備忘錄對象從負(fù)責(zé)人對象中取出。注意此時僅能得到 MementoIF接口,因此無法讀出此對象的內(nèi)部狀態(tài)
           177:             (3)將發(fā)起人對象的狀態(tài)恢復(fù)成備忘錄對象所存儲起來的狀態(tài),,由于發(fā)起人對象的內(nèi)部類Memento實現(xiàn)了MementoIF接口
           178:                  這個內(nèi)部類是傳入的備忘錄對象的真實類型,因此發(fā)起人對象可以利用內(nèi)部類Memento 的私有 接口讀出此對象的內(nèi)部狀態(tài)
           179:                  
           180: 存儲多個狀態(tài)的備忘錄模式:
           181:         //發(fā)起人角色
           182:         import java.util.Vector;
           183:         import java.util.Enumeration;
           184:         
           185:         public class Originator{
           186:             private Vector states;
           187:             private int index;
           188:             
           189:             public Originator(){
           190:                 states = new Vector();
           191:                 index = 0;
           192:             }
           193:             
           194:             public Memento createMementor(){
           195:                 return new Mementor(states,index);
           196:             }
           197:             
           198:             public void restoreMementor(Mementor memento){
           199:                 states = memento.getStates();
           200:                 index = memento.getIndex();
           201:             }
           202:             
           203:             public void setState(String state){
           204:                 this.states.addElement(state);
           205:                 index ++;
           206:             }
           207:             
           208:             //輔助方法,打印出所有的狀態(tài)
           209:             public void printStates(){
           210:                 System.out.println("Total number of states: " + index);
           211:                 for(Enumeration e = states.elements();e.hasMoreElements();){
           212:                     system.out.println(e.nextElement());
           213:                 }
           214:             }
           215:         } 
           216:         
           217:         //備忘錄角色
           218:         import java.util.Vector;
           219:         
           220:         public class Memento{
           221:             private Vector states;
           222:             private int index;
           223:             
           224:             public Memento(Vector states,int index){
           225:                 this.states = (Vector)states.clone();
           226:                 this.index = index;
           227:             }
           228:             
           229:             //狀態(tài)取值方法
           230:             Vector getStates(){
           231:                 return states;
           232:             }
           233:             
           234:             //檢查點取值方法
           235:             int getIndex(){
           236:                 return this.index;
           237:             }
           238:         }
           239: ******************備忘錄的構(gòu)造子克隆了傳入的states,然后將克隆存入到備忘錄對象內(nèi)部,這是一個重要的細(xì)節(jié),因為不這樣的話,將會
           240:           將會造成客戶端和備忘錄對象持有對同一個Vector對象的引用,也可以同時修改這個Vector對象,會造成系統(tǒng)崩潰。
           241:           
           242:         //負(fù)責(zé)人角色
           243:         import java.util.Vector;
           244:         
           245:         public class Caretaker{
           246:             private Originator o;
           247:             private Vector mementos = new Vector();
           248:             private int current;
           249:             
           250:             public Caretaker(Originator o){
           251:                 this.o = o;
           252:                 current = 0;
           253:             }
           254:             
           255:             public int createMemento(){
           256:                 Memento memento = o.createMemento();
           257:                 mementos.addElement(memento);
           258:                 return current ++;
           259:             }
           260:             
           261:             //將發(fā)起人恢復(fù)到某個檢查點
           262:             public void restoreMemento(int index){
           263:                 Memento memento = (Memento)mementos.elementAt(index);
           264:                 o.restoreMemento(memento);
           265:             }
           266:             
           267:             //某個檢查點刪除
           268:             public void removeMemento(int index){
           269:                 mementos.removeElementAt(index);
           270:             }
           271:         }
           272:         
           273:         //客戶端
           274:         public class Client{
           275:             private static Originator o = new Originator();
           276:             private static Caretaker c = new Caretaker(o);
           277:             public static void main(String[] args){
           278:                 //改變狀態(tài)
           279:                 o.setState("state 0");
           280:                 //建立一個檢查點
           281:                 c.createMemento();
           282:                 //改變狀態(tài)
           283:                 o.setState("state 1");
           284:                 
           285:                 c.createMemento();
           286:                 
           287:                 o.setState("state 2");
           288:                 
           289:                 c.createMemento();
           290:                 
           291:                 o.setState("state 3");
           292:                 
           293:                 c.createMemento();
           294:                 
           295:                 o.setState("state 4");
           296:                 
           297:                 c.createMemento();
           298:                 
           299:                 o.printStates();
           300:                 
           301:                 //恢復(fù)到第二個檢查點
           302:                 System.out.println("Restoring to 2");
           303:                 
           304:                 c.restoreMemento(2);
           305:                 
           306:                 o.printStates();
           307:                 
           308:                 System.out.println("Restoring to 0");
           309:                 
           310:                 c.restoreMemento(0);
           311:                 
           312:                 o.printStates();
           313:                 
           314:                 System.out.println("Restoring to 3");
           315:                 
           316:                 c.restoreMemento(3);
           317:                 
           318:                 o.printStates();
           319:                 
           320:                 
           321:             }
           322:         }
           323:         
           324: 自述歷史模式(備忘錄模式的一個變種):
           325:         //窄接口
           326:         public interface MementoIF{}
           327:         
           328:         //發(fā)起人角色
           329:         public class Originator{
           330:             public String state;
           331:             
           332:             public Originator(){}
           333:             
           334:             public void changeState(String state){
           335:                 this.state = state;
           336:                 System.out.println("State has been changed to : " + state);
           337:             }
           338:             
           339:             public Memento createMemento(){
           340:                 return new Memento(this);
           341:             }
           342:             
           343:             public void restoreMemento(MementoIF memento){
           344:                 Memento m = (Memento)memento;
           345:                 changeState(m.state);
           346:             }
           347:             
           348:             class Memento implements MementoIF{
           349:                 private String state;
           350:                 
           351:                 private String getState(){
           352:                     return state;
           353:                 }
           354:                 
           355:                 private Memento(Originator o){
           356:                     this.state = o.state;
           357:                 }
           358:             }
           359:         }
           360:         
           361:         //客戶端
           362:         public class Client{
           363:             private static Originator o;
           364:             private static MementoIF memento;
           365:             
           366:             public static void main(String args[]){
           367:                 o = new Originator();
           368:                 o.changeState("State 1");
           369:                 memento = o.createMemento();
           370:                 o.changeState("State 2");
           371:                 o.restoreMemento(memento);
           372:             }
           373:         }
           374:         

          模式的優(yōu)缺點:
          由于“自述歷史”作為一個備忘錄模式的特殊實現(xiàn)形式非常簡單易懂,它可能是備忘錄模式最為流行的實現(xiàn)形式。
          備忘錄模式的操作過程
          1、客戶端為發(fā)起人角色創(chuàng)建一個備忘錄對象。
          2、調(diào)用發(fā)起人對象的某個操作,這個操作是可以撤銷的。
          3、檢查發(fā)起人對象所出狀態(tài)的有效性。檢查的方式可以是發(fā)起人對象的內(nèi)部自查,也可以由某個外部對象進(jìn)行檢查。
          4、如果需要的話,將發(fā)起人的操作撤銷,也就是說根據(jù)備忘錄對象的記錄,將發(fā)起人對象的狀態(tài)恢復(fù)過來。
          “假如”協(xié)議模式的操作過程:
          1、將發(fā)起人對象做一個拷貝。
          2、在拷貝上執(zhí)行某個操作。
          3、檢查這個拷貝的狀態(tài)是否有效和自恰。
          4、如果檢查結(jié)果是無效或者不自恰的,那么扔掉這個拷貝,并觸發(fā)異常處理程序;相反,如果檢查是有效和自恰的,那么在原對象上執(zhí)行這個操作
          顯然這一做法對于撤銷一個操作并恢復(fù)操作前狀態(tài)較為復(fù)雜和困難的發(fā)起人對象來說是一個較為謹(jǐn)慎和有效的做法。
          “假如”協(xié)議模式的優(yōu)點和缺點
          具體來說,這個做法的長處是可以保證發(fā)起人對象永遠(yuǎn)不會處于無效或不自恰的狀態(tài)上,這樣作的短處是成功的操作必須執(zhí)行兩次。
          如果操作的成功率較低的話,這樣做就比較劃算,反之就不太劃算。
          使用備忘錄模式的優(yōu)點和缺點
          一、備忘錄模式的優(yōu)點
          1、有時一些發(fā)起人對象的內(nèi)部信息必須保存在發(fā)起人對象以外的地方,但是必須要由發(fā)起人對象自己讀取,這時,
             使用備忘錄模式可以把復(fù)雜的發(fā)起人內(nèi)部信息對其他的對象屏蔽起來,從而可以恰當(dāng)?shù)乇3址庋b的邊界。
          2、本模式簡化了發(fā)起人類。發(fā)起人不再需要管理和保存其內(nèi)部狀態(tài)的一個個版本,客戶端可以自行管理他們所需
             要的這些狀態(tài)的版本。
          3、當(dāng)發(fā)起人角色的狀態(tài)改變的時候,有可能這個狀態(tài)無效,這時候就可以使用暫時存儲起來的備忘錄將狀態(tài)復(fù)原。
          二、備忘錄模式的缺點:
          1、如果發(fā)起人角色的狀態(tài)需要完整地存儲到備忘錄對象中,那么在資源消耗上面?zhèn)渫泴ο髸馨嘿F。
          2、當(dāng)負(fù)責(zé)人角色將一個備忘錄 存儲起來的時候,負(fù)責(zé)人可能并不知道這個狀態(tài)會占用多大的存儲空間,從而無法
             提醒用戶一個操作是否很昂貴。882——P
          3、當(dāng)發(fā)起人角色的狀態(tài)改變的時候,有可能這個協(xié)議無效。如果狀態(tài)改變的成功率不高的話,不如采取“假如”協(xié)議模式。

          posted on 2011-02-08 16:48 人在江湖 閱讀(3545) 評論(0)  編輯  收藏 所屬分類: design pattern
          主站蜘蛛池模板: 馆陶县| 定西市| 乐清市| 澎湖县| 吉安市| 沁水县| 滁州市| 闽侯县| 连平县| 双城市| 台东市| 加查县| 兖州市| 丰县| 洪洞县| 西充县| 盘山县| 栾城县| 栾川县| 吉木乃县| 贵港市| 伊宁市| 灵璧县| 惠东县| 察隅县| 穆棱市| 双峰县| 聂拉木县| 东城区| 彩票| 沭阳县| 普兰店市| 鹰潭市| 临沭县| 淮阳县| 卢湾区| 辽中县| 苍梧县| 靖江市| 贞丰县| 涡阳县|