一、什么是備忘錄模式備忘錄這個詞匯大家應(yīng)該都不陌生,我就經(jīng)常使用備忘錄來記錄一些比較重要的或者容易遺忘的信息,與之相關(guān)的最常見的應(yīng)用有許多,比如游戲存檔,我們玩游戲的時候肯定有存檔功能,旨在下一次登錄游戲時可以從上次退出的地方繼續(xù)游戲,或者對復(fù)活點(diǎn)進(jìn)行存檔,如果掛掉了則可以讀取復(fù)活點(diǎn)的存檔信息重新開始。與之相類似的就是數(shù)據(jù)庫的事務(wù)回滾,或者重做日志redo log等。 備忘錄模式(Memento),在不破壞封裝性的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存著這個狀態(tài)。這樣以后就可將該對象恢復(fù)到原先保存的狀態(tài)。UML結(jié)構(gòu)圖如下: 其中,Originator是發(fā)起人,負(fù)責(zé)創(chuàng)建一個備忘錄Memento,用以記錄當(dāng)前時刻它的內(nèi)部狀態(tài),并可使用備忘錄恢復(fù)內(nèi)部狀態(tài);Memento是備忘錄,負(fù)責(zé)存儲Originator對象的內(nèi)部狀態(tài),并可防止Originator以外的其他對象訪問備忘錄Memento;Caretaker是管理者,負(fù)責(zé)保存好備忘錄的Memento,不能對備忘錄的內(nèi)容進(jìn)行操作或檢查。 1. 發(fā)起人角色記錄當(dāng)前時刻的內(nèi)部狀態(tài),并負(fù)責(zé)創(chuàng)建和恢復(fù)備忘錄數(shù)據(jù),允許訪問返回到先前狀態(tài)所需的所有數(shù)據(jù)。 1 public class Originator { 2 3 private String state; 4 5 public String getState() { 6 return state; 7 } 8 9 public void setState(String state) {10 this.state = state;11 }12 13 public Memento createMento() {14 return (new Memento(state));15 }16 17 public void setMemento(Memento memento) {18 state = memento.getState();19 }20 21 public void show() {22 System.out.println("state = " + state);23 }24 25 } 2. 備忘錄角色負(fù)責(zé)存儲Originator發(fā)起人對象的內(nèi)部狀態(tài),在需要的時候提供發(fā)起人需要的內(nèi)部狀態(tài)。 1 public class Memento { 2 3 private String state; 4 5 public Memento(String state) { 6 this.state = state; 7 } 8 9 public String getState() {10 return state;11 }12 13 } 3. 備忘錄管理員角色對備忘錄進(jìn)行管理、保存和提供備忘錄,只能將備忘錄傳遞給其他角色。 1 public class Caretaker { 2 3 private Memento memento; 4 5 public Memento getMemento() { 6 return memento; 7 } 8 9 public void setMemento(Memento memento) {10 this.memento = memento;11 }12 13 } 4. Client客戶端下面編寫一小段代碼測試一下,即先將狀態(tài)置為On,保存后再將狀態(tài)置為Off,然后通過備忘錄管理員角色恢復(fù)初始狀態(tài)。 1 public class Client { 2 3 public static void main(String[] args) { 4 Originator originator = new Originator(); 5 originator.setState("On"); //Originator初始狀態(tài) 6 originator.show(); 7 8 Caretaker caretaker = new Caretaker(); 9 caretaker.setMemento(originator.createMento());10 11 originator.setState("Off"); //Originator狀態(tài)變?yōu)镺ff12 originator.show();13 14 originator.setMemento(caretaker.getMemento()); //回復(fù)初始狀態(tài)15 originator.show();16 }17 18 } 運(yùn)行結(jié)果如下: 二、備忘錄模式的應(yīng)用1. 何時使用
2. 方法
3. 優(yōu)點(diǎn)
4. 缺點(diǎn)
5. 使用場景
6. 應(yīng)用實(shí)例
7. 注意事項(xiàng)
三、備忘錄模式的實(shí)現(xiàn)下面以游戲存檔為例,看一下如何用備忘錄模式實(shí)現(xiàn)。UML圖如下: 1. 游戲角色簡單記錄了游戲角色的生命力、攻擊力、防御力,通過saveState()方法來保存當(dāng)前狀態(tài),通過recoveryState()方法來恢復(fù)角色狀態(tài)。 1 public class GameRole { 2 3 private int vit; //生命力 4 private int atk; //攻擊力 5 private int def; //防御力 6 7 public int getVit() { 8 return vit; 9 }10 public void setVit(int vit) {11 this.vit = vit;12 }13 public int getAtk() {14 return atk;15 }16 public void setAtk(int atk) {17 this.atk = atk;18 }19 public int getDef() {20 return def;21 }22 public void setDef(int def) {23 this.def = def;24 }25 26 //狀態(tài)顯示27 public void stateDisplay() {28 System.out.println("角色當(dāng)前狀態(tài):");29 System.out.println("體力:" + this.vit);30 System.out.println("攻擊力:" + this.atk);31 System.out.println("防御力: " + this.def);32 System.out.println("-----------------");33 }34 35 //獲得初始狀態(tài)36 public void getInitState() {37 this.vit = 100;38 this.atk = 100;39 this.def = 100;40 }41 42 //戰(zhàn)斗后43 public void fight() {44 this.vit = 0;45 this.atk = 0;46 this.def = 0;47 }48 49 //保存角色狀態(tài)50 public RoleStateMemento saveState() {51 return (new RoleStateMemento(vit, atk, def));52 }53 54 //恢復(fù)角色狀態(tài)55 public void recoveryState(RoleStateMemento memento) {56 this.vit = memento.getVit();57 this.atk = memento.getAtk();58 this.def = memento.getDef();59 }60 61 } 2. 角色狀態(tài)存儲箱備忘錄類,用于存儲角色狀態(tài)。 1 public class RoleStateMemento { 2 3 private int vit; //生命力 4 private int atk; //攻擊力 5 private int def; //防御力 6 7 public RoleStateMemento(int vit, int atk, int def) { 8 this.vit = vit; 9 this.atk = atk;10 this.def = def;11 }12 13 public int getVit() {14 return vit;15 }16 17 public void setVit(int vit) {18 this.vit = vit;19 }20 21 public int getAtk() {22 return atk;23 }24 25 public void setAtk(int atk) {26 this.atk = atk;27 }28 29 public int getDef() {30 return def;31 }32 33 public void setDef(int def) {34 this.def = def;35 }36 37 } 3. 角色狀態(tài)管理者備忘錄管理者。 1 public class RoleStateCaretaker { 2 3 private RoleStateMemento memento; 4 5 public RoleStateMemento getMemento() { 6 return memento; 7 } 8 9 public void setMemento(RoleStateMemento memento) {10 this.memento = memento;11 }12 13 } 4. Client客戶端下面編寫一個簡單的程序測試一下,編寫邏輯大致為打boss前存檔,打boss失敗了,讀檔。 1 public class Client { 2 3 public static void main(String[] args) { 4 //打boss前 5 GameRole gameRole = new GameRole(); 6 gameRole.getInitState(); 7 gameRole.stateDisplay(); 8 9 //保存進(jìn)度10 RoleStateCaretaker caretaker = new RoleStateCaretaker();11 caretaker.setMemento(gameRole.saveState());12 13 //打boss失敗14 gameRole.fight();15 gameRole.stateDisplay();16 17 //恢復(fù)狀態(tài)18 gameRole.recoveryState(caretaker.getMemento());19 gameRole.stateDisplay();20 }21 22 } 運(yùn)行結(jié)果如下: |
|