備忘錄模式(Memento),在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,這樣就可以將該對象狀態恢復到原先保存的狀態。
備忘錄模式UML類圖:
由上圖可知,Originator(發起人)類:負責創建一個備忘錄Memento,用以記錄當前時刻它的內部狀態,並可使用備忘錄恢復內部狀態,Originator可根據需要決定Memento存儲Originator的哪些內部狀態 。
Memento(備忘錄):負責存儲Originator對象的內部狀態,並可防止Originator以外的其它對象訪問備忘錄Memento。備忘錄有兩個接口,Caretaker只能看到Memento的窄接口,它只能將備忘錄傳遞給其它對象,Originator看到一個寬接口允許它訪問返回到先前狀態所需的所有數據。
Caretaker(管理者):負責保存好備忘錄Memento,不能對備忘錄的內容進行操作或檢查。
備忘錄模式(Memento)實現:
[csharp]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Memento
{
/*
* 備忘錄Memento類,負責存儲Originator對象的內部狀態,
* 並可防止Originator以外的其它對象訪問備忘錄。
*/
class Memento
{
private string state;
public Memento(string state)//構造方法將相關數據導入
{
this.state = state;
}
public string getState()//需要保存的數據屬性,可以是多個
{
return this.state;
}
}
/*
* Originator發起人類,負責創建一個備忘錄Memento,
* 用以記錄當前時刻它的內部狀態,並可以使用備忘錄恢復內部狀態。
*/
class Originator
{
private string state;//需要保存屬性可能有多個
public string getState()
{
return this.state;
}
public void setState(string state)
{
this.state = state;
}
public Memento CreateMemento()//創建備忘錄,將當前需要保存的信息導入並實例化出一個Memento對象
{
return new Memento(this.getState());
}
public void RecoveryMemento(Memento memento)//恢復備忘錄,將Memento導入並將相關數據恢復
{
this.state = memento.getState();
}
public void show()//顯示數據
{
Console.WriteLine("state:" + this.state);
}
}
/*
* Caretaker負責保存好備忘錄Memento
*/
class Caretaker
{
private Memento memento;
public Memento getMemento()//得到備忘錄
{
return this.memento;
}
public void setMemento(Memento memento)//設置備忘錄
{
this.memento = memento;
}
}
}
客戶端:
[csharp]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Memento
{
class Program
{
static void Main(string[] args)
{
Originator o = new Originator();
Console.WriteLine("Originator對象o的初始狀態...");
o.setState("on");
o.show();
Caretaker c = new Caretaker();
/*
* 保存狀態時,由於有了很好的封裝,可以隱藏Originator的實現細節
*/
c.setMemento(o.CreateMemento());
Console.WriteLine("Originator對象o改變了狀態屬性為“off”...");
o.setState("off");
o.show();
Console.WriteLine("恢復初始狀態...");
o.RecoveryMemento(c.getMemento());
o.show();
Console.Read();
}
}
}
備忘錄模式總結:
(1)使用備忘錄模式,也就是將要保存的細節給封裝在了Memento中,哪一天要更改保存的細節也不用影響客戶端了。
(2)備忘錄模式比較適用於功能比較復雜的,但需要維護或記錄屬性歷史的類,或者需要保存的屬性只是眾多屬性的一小部分時,Originator可以根據保存的Memento信息還原到前一狀態。
(3)如果在某個系統中使用命令模式時,需要實現命令模式的撤銷功能,那麼命令模式可以使用備忘錄模式來存儲可撤銷操作的狀態。
(4)在當角色的狀態改變的時候有可能這個狀態無效,這時,就可以使用暫時存儲起來的備忘錄將狀態復原。
備忘錄模式案例——游戲進度備忘
[csharp]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MementoExample
{
class Memento
{
}
//游戲角色類
class GameRole
{
//生命力
private int vit;
//攻擊力
private int atk;
//防御力
private int def;
public int getVit()
{
return this.vit;
}
public void setVit(int vit)
{
this.vit = vit;
}
public int getAtk()
{
return this.atk;
}
public void setAtk(int atk)
{
this.atk = atk;
}
public int getDef()
{
return this.def;
}
public void setzdef(int def)
{
this.def = def;
}
/*設置初始狀態*/
public void InitState()
{
this.vit = 100;
this.atk = 100;
this.def = 100;
}
/*當前狀態顯示*/
public void ShowState()
{
Console.WriteLine("角色當前狀態:");
Console.WriteLine("生命力:{0}",this.vit);
Console.WriteLine("攻擊力:{0}",this.atk);
Console.WriteLine("防御力:{0}",this.def);
}
/*戰斗*/
public void Fight()
{
this.vit = 0;
this.atk = 0;
this.def = 0;
}
/*保存角色狀態*/
public RoleStateMemento SaveRoleState()
{
return new RoleStateMemento(this.vit,this.atk,this.def);
}
/*恢復角色狀態*/
public void RecoveryState(RoleStateMemento rsm)
{
this.vit = rsm.getVit();
this.atk = rsm.getAtk();
this.def = rsm.getDef();
}
}
/*角色狀態備忘錄*/
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 int getVit()
{
return this.vit;
}
public void setVit(int vit)
{
this.vit = vit;
}
public int getAtk()
{
return this.atk;
}
public void setAtk(int atk)
{
this.atk = atk;
}
public int getDef()
{
return this.def;
}
public void setzdef(int def)
{
this.def = def;
}
}
/*游戲管理者類*/
class RoleStateCaretaker
{
private RoleStateMemento rsm;
public RoleStateMemento getRsm()
{
return this.rsm;
}
public void setRsm(RoleStateMemento rsm)
{
this.rsm = rsm;
}
}
}
客戶端:
[csharp]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MementoExample
{
class Program
{
static void Main(string[] args)
{
//大戰boss前
Console.WriteLine("大戰boss前...");
GameRole gr = new GameRole();
gr.InitState();
gr.ShowState();
//保存進度
RoleStateCaretaker rsc = new RoleStateCaretaker();
rsc.setRsm(gr.SaveRoleState());
//大戰boss,損耗嚴重
Console.WriteLine("大戰boss,損耗嚴重...");
gr.Fight();
gr.ShowState();
//恢復進度
Console.WriteLine("恢復進度...");
gr.RecoveryState(rsc.getRsm());
gr.ShowState();
Console.Read();
}
}
}
運行結果: