該項(xiàng)目源碼地址:https://github.com/ggb2312/Code/tree/master/java-basic/design-pattern
(設(shè)計模式相關(guān)代碼與筆記)
1. 定義
在不破壞封裝性的前提下榴都,保存一個對象的某個狀態(tài)尔艇,以便在適當(dāng)?shù)臅r候恢復(fù)對象驰坊。
2. 適用場景
- 保存及恢復(fù)數(shù)據(jù)相關(guān)業(yè)務(wù)場景
- 后悔的時候晌涕,即想恢復(fù)到之前的狀態(tài)
比如:wps之類的文本編輯器
3. 類圖與角色
備忘錄模式主要包含入下幾個角色:
Originator:原發(fā)器固蛾。負(fù)責(zé)創(chuàng)建一個備忘錄,用以記錄當(dāng)前對象的內(nèi)部狀態(tài),通過使用它來利用備忘錄恢復(fù)內(nèi)部狀態(tài)。同時原發(fā)器還可以根據(jù)需要決定Memento存儲Originator的那些內(nèi)部狀態(tài)荧止。
?Memento:備忘錄。用于存儲Originator的內(nèi)部狀態(tài)阶剑,并且可以防止Originator以外的對象訪問Memento跃巡。在備忘錄Memento中有兩個接口,其中Caretaker只能看到備忘錄中的窄接口牧愁,它只能將備忘錄傳遞給其他對象素邪。Originator可以看到寬接口,允許它訪問返回到先前狀態(tài)的所有數(shù)據(jù)
Caretaker:負(fù)責(zé)人递宅。負(fù)責(zé)保存好備忘錄娘香,不能對備忘錄的內(nèi)容進(jìn)行操作和訪問,只能夠?qū)渫泜鬟f給其他對象办龄。
在備忘錄模式中,最重要的就是備忘錄Memento了淋昭。我們都是備忘錄中存儲的就是原發(fā)器的部分或者所有的狀態(tài)信息俐填,而這些狀態(tài)信息是不能夠被其他對象所訪問了,也就是說我們是不可能在備忘錄之外的對象來存儲這些狀態(tài)信息翔忽,如果暴漏了內(nèi)部狀態(tài)信息就違反了封裝的原則英融,故備忘錄是除了原發(fā)器外其他對象都是不可以訪問的。
? 所以為了實(shí)現(xiàn)備忘錄模式的封裝歇式,我們需要對備忘錄的訪問做些控制:
對原發(fā)器:可以訪問備忘錄里的所有信息驶悟。
對負(fù)責(zé)人:不可以訪問備忘錄里面的數(shù)據(jù),但是他可以保存?zhèn)渫洸⑶铱梢詫渫泜鬟f給其他對象材失。
其他對象:不可訪問也不可以保存痕鳍,它只負(fù)責(zé)接收從負(fù)責(zé)人那里傳遞過來的備忘錄同時恢復(fù)原發(fā)器的狀態(tài)。
所以就備忘錄模式而言理想的情況就是只允許生成該備忘錄的那個原發(fā)器訪問備忘錄的內(nèi)部狀態(tài)。
4. 相關(guān)設(shè)計模式
備忘錄模式和狀態(tài)模式
備忘錄模式是對象表示狀態(tài)笼呆,狀態(tài)模式是用類來表示狀態(tài)熊响。
5. 模式實(shí)例
背景:我們就以游戲挑戰(zhàn)BOSS為實(shí)現(xiàn)場景,在挑戰(zhàn)BOSS之前诗赌,角色的血量汗茄、藍(lán)量都是滿值,然后存檔铭若,在大戰(zhàn)BOSS時洪碳,由于操作失誤導(dǎo)致血量和藍(lán)量大量損耗,所以只好恢復(fù)到剛剛開始的存檔點(diǎn)叼屠,繼續(xù)進(jìn)行大戰(zhàn)BOSS了偶宫。這里使用備忘錄模式來實(shí)現(xiàn)。
(1)首先是游戲角色類:Role
public class Role {
private int bloodFlow;//血量
private int magicPoint;//藍(lán)量
public Role(int bloodFlow,int magicPoint){
this.bloodFlow = bloodFlow;
this.magicPoint = magicPoint;
}
public int getBloodFlow() {
return bloodFlow;
}
public void setBloodFlow(int bloodFlow) {
this.bloodFlow = bloodFlow;
}
public int getMagicPoint() {
return magicPoint;
}
public void setMagicPoint(int magicPoint) {
this.magicPoint = magicPoint;
}
public void display(){
System.out.println("用戶當(dāng)前狀態(tài):");
System.out.println("血量:" + getBloodFlow() + ";藍(lán)量:" + getMagicPoint());
}
public Memento saveMemento(){
return new Memento(getBloodFlow(), getMagicPoint());
}
public void restoreMemento(Memento memento){
this.bloodFlow = memento.getBloodFlow();
this.magicPoint = memento.getMagicPoint();
}
}
(2)備忘錄:Memento
class Memento {
private int bloodFlow;
private int magicPoint;
public int getBloodFlow() {
return bloodFlow;
}
public int getMagicPoint() {
return magicPoint;
}
public Memento(int bloodFlow,int magicPoint){
this.bloodFlow = bloodFlow;
this.magicPoint = magicPoint;
}
}
(3)負(fù)責(zé)人:Caretaker
public class Caretaker {
Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
(4)客戶端:Client
public class Client {
public static void main(String[] args) {
//打BOSS之前:血环鲤、藍(lán)全部滿值
Role role = new Role(100, 100);
System.out.println("----------大戰(zhàn)BOSS之前----------");
role.display();
//保持進(jìn)度
Caretaker caretaker = new Caretaker();
caretaker.memento = role.saveMemento();
//大戰(zhàn)BOSS纯趋,快come Over了
role.setBloodFlow(20);
role.setMagicPoint(20);
System.out.println("----------大戰(zhàn)BOSS----------");
role.display();
//恢復(fù)存檔
role.restoreMemento(caretaker.getMemento());
System.out.println("----------恢復(fù)----------");
role.display();
}
}
6. 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 為用戶提供一種可恢復(fù)機(jī)制
- 存檔信息的封裝
缺點(diǎn):
- 資源占用
7. 擴(kuò)展-JDK1.7源碼以及框架中的備忘錄模式
org.springframework.binding.message.StateManageableMessageContext