- 又叫快照模式,在不破壞封裝性的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)次和,以便以后需要時可以將該對象恢復(fù)到之前的狀態(tài)。
結(jié)構(gòu)
- 發(fā)起人(Originator)角色:記錄當(dāng)前時刻的內(nèi)部狀態(tài)信息羊精,提供創(chuàng)建備忘錄和恢復(fù)備忘錄數(shù)據(jù)的功能斯够,實(shí)現(xiàn)其他業(yè)務(wù)功能,它可以訪問備忘錄里的所有信息喧锦。
- 備忘錄(Memento)角色:負(fù)責(zé)存儲發(fā)起人的內(nèi)部狀態(tài)读规,在需要的時候提供這些內(nèi)部狀態(tài)給發(fā)起人。
- 管理者(Caretaker)角色:對備忘錄進(jìn)行管理燃少,提供保存與獲取備忘錄的功能束亏,但其不能對備忘錄的內(nèi)容進(jìn)行訪問與修改。
備忘錄有兩個等效的接口:
- 窄接口:管理者(Caretaker)對象(和其他發(fā)起人對象之外的任何對象)看到的是備忘錄的窄接口(narror Interface)阵具,這個窄接口只允許他把備忘錄對象傳給其他的對象碍遍。
- 寬接口:與管理者看到的窄接口相反,發(fā)起人對象可以看到一個寬接口(wide Interface)阳液,這個寬接口允許它讀取所有的數(shù)據(jù)怕敬,以便根據(jù)這些數(shù)據(jù)恢復(fù)這個發(fā)起人對象的內(nèi)部狀態(tài)。
案例
白箱備忘錄模式
- 備忘錄角色對任何對象都提供一個接口帘皿,即寬接口东跪,備忘錄角色的內(nèi)部所存儲的狀態(tài)就對所有對象公開了。
// 游戲角色類(發(fā)起人角色)
// GameRole.java
public class GameRole {
private int vit; // 生命力
private int atk; // 攻擊力
private int def; // 防御力
// 初始化狀態(tài)
public void initState(){
this.vit = 100;
this.atk = 100;
this.def = 100;
}
// 戰(zhàn)斗的方法
public void fight(){
this.vit = 0;
this.atk = 0;
this.def = 0;
}
// 保存狀態(tài)功能
public RoleStateMemento saveState(){
return new RoleStateMemento(vit,atk,def);
}
// 恢復(fù)角色狀態(tài)
public void recoverState(RoleStateMemento roleStateMemento){
// 將備忘錄對象中存儲的狀態(tài)賦值給當(dāng)前對象的成員
this.vit = roleStateMemento.getVit();
this.atk = roleStateMemento.getAtk();
this.def = roleStateMemento.getDef();
}
// 展示狀態(tài)功能
public void stateDisplay(){
System.out.println("角色生命力:" + vit);
System.out.println("角色攻擊力:" + atk);
System.out.println("角色防御力:" + def);
}
}
// 備忘錄角色類
// RoleStateMemento.java
public class RoleStateMemento {
private int vit; // 生命力
private int atk; // 攻擊力
private int def; // 防御力
public RoleStateMemento(int vit, int atk, int def) {
this.vit = vit;
this.atk = atk;
this.def = def;
}
public RoleStateMemento() {
}
public int getVit() {
return vit;
}
public void setVit(int vit) {
this.vit = vit;
}
public int getAtk() {
return atk;
}
public void setAtk(int atk) {
this.atk = atk;
}
public int getDef() {
return def;
}
public void setDef(int def) {
this.def = def;
}
}
// 備忘錄對象管理角色
// RoleStateCaretaker.java
public class RoleStateCaretaker {
// 聲明RoleStateMemento類型的變量
private RoleStateMemento roleStateMemento;
public void setRoleStateMemento(RoleStateMemento roleStateMemento){
this.roleStateMemento = roleStateMemento;
}
public RoleStateMemento getRoleStateMemento() {
return roleStateMemento;
}
}
// Client.java
public class Client {
public static void main(String[] args) {
System.out.println("--------- 大戰(zhàn)boss前 ----------");
// 創(chuàng)建一個游戲角色對象
GameRole gameRole = new GameRole();
gameRole.initState(); // 初始化狀態(tài)操作
gameRole.stateDisplay();
// 將該游戲角色內(nèi)部狀態(tài)進(jìn)行備份
RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
roleStateCaretaker.setRoleStateMemento(gameRole.saveState());
System.out.println("--------- 大戰(zhàn)boss后 ----------");
// 損耗嚴(yán)重
gameRole.fight();
gameRole.stateDisplay();
System.out.println("--------- 恢復(fù)狀態(tài) ----------");
gameRole.recoverState(roleStateCaretaker.getRoleStateMemento());
gameRole.stateDisplay();
}
}
- 在白箱備忘錄中鹰溜,所有的類都可以訪問到備忘錄角色狀態(tài)中的數(shù)據(jù)虽填,破壞了封裝性。
黑箱備忘錄模式
- 備忘錄角色對發(fā)起人對象提供一個寬接口曹动,而為其他對象提供一個窄接口斋日。在Java語言中,實(shí)現(xiàn)雙重接口的辦法就是將備忘錄類設(shè)計成發(fā)起人類的內(nèi)部成員類墓陈。
// 備忘錄接口恶守,對外提供的窄接口
// Memento.java
public interface Memento {
}
// 游戲角色類(發(fā)起人角色)
// GameRole.java
public class GameRole {
private int vit; // 生命力
private int atk; // 攻擊力
private int def; // 防御力
// 初始化狀態(tài)
public void initState(){
this.vit = 100;
this.atk = 100;
this.def = 100;
}
// 戰(zhàn)斗的方法
public void fight(){
this.vit = 0;
this.atk = 0;
this.def = 0;
}
// 保存狀態(tài)功能
public Memento saveState(){
return new RoleStateMemento(vit,atk,def);
}
// 恢復(fù)角色狀態(tài)
public void recoverState(Memento memento){
RoleStateMemento roleStateMemento = (RoleStateMemento)memento;
// 將備忘錄對象中存儲的狀態(tài)賦值給當(dāng)前對象的成員
this.vit = roleStateMemento.getVit();
this.atk = roleStateMemento.getAtk();
this.def = roleStateMemento.getDef();
}
// 展示狀態(tài)功能
public void stateDisplay(){
System.out.println("角色生命力:" + vit);
System.out.println("角色攻擊力:" + atk);
System.out.println("角色防御力:" + def);
}
private class RoleStateMemento implements Memento{
private int vit; // 生命力
private int atk; // 攻擊力
private int def; // 防御力
public RoleStateMemento(int vit, int atk, int def) {
this.vit = vit;
this.atk = atk;
this.def = def;
}
public RoleStateMemento() {
}
public int getVit() {
return vit;
}
public void setVit(int vit) {
this.vit = vit;
}
public int getAtk() {
return atk;
}
public void setAtk(int atk) {
this.atk = atk;
}
public int getDef() {
return def;
}
public void setDef(int def) {
this.def = def;
}
}
}
// 備忘錄對象管理對象
// RoleStateCaretaker.java
public class RoleStateCaretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
// Client.java
public class Client {
public static void main(String[] args) {
System.out.println("--------- 大戰(zhàn)boss前 ----------");
// 創(chuàng)建一個游戲角色對象
GameRole gameRole = new GameRole();
gameRole.initState(); // 初始化狀態(tài)操作
gameRole.stateDisplay();
// 將該游戲角色內(nèi)部狀態(tài)進(jìn)行備份
RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
roleStateCaretaker.setMemento(gameRole.saveState());
System.out.println("--------- 大戰(zhàn)boss后 ----------");
// 損耗嚴(yán)重
gameRole.fight();
gameRole.stateDisplay();
System.out.println("--------- 恢復(fù)狀態(tài) ----------");
gameRole.recoverState(roleStateCaretaker.getMemento());
gameRole.stateDisplay();
}
}
- 這個案例中深化了對于接口的認(rèn)識,該段代碼本質(zhì)就是通過接口來向外部不同的類提供不同程度的內(nèi)部暴露贡必。