备忘录模式(Memento Pattern)
保存一个对象的某个状态,以便在适当的时候恢复它的这个状态。有时需要在某个时刻捕获对象的内部状态,并且能够在稍后恢复到该状态。 这种情况在操作出错时很有用, 像具有撤销操作的计算器场景。
Memento 模式使用三个 actor 类:Originator 在 Memento 对象中创建和存储状态;Memento 包含要恢复的对象的状态; Caretaker 对象负责从 Memento 恢复对象状态。
意图:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样可以在以后将对象恢复到原先保存的状态。
何时使用:
记录一个对象的内部状态,目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态。比如绘图过程的撤销操作。
应用示例:
- Windows 里的 ctri + z。
- IE 中的后退。
- 数据库的事务管理。
etc...
如何解决:
通过一个备忘录类专门存储对象状态。
关键代码:
客户不与备忘录类(Memento)耦合,与备忘录管理类(Caretaker)耦合。
优点:
- 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史状态。
- 实现了信息的封装,使得用户不需要关心状态的保存细节。
缺点:
消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。
如果 Originator 对象非常庞大,那么 Memento 对象的大小也会很大并且会占用大量内存。
具体示例 e.g.:
// Originator
public class GamePlayer {
// 遊戲角色的生命值
private int mHp;
// 遊戲角色的經驗值
private int mExp;
public GamePlayer(int hp, int exp)
{
mHp = hp;
mExp = exp;
}
public GameMemento saveToMemento()
{
return new GameMemento(mHp, mExp);
}
public void restoreFromMemento(GameMemento memento)
{
mHp = memento.getGameHp();
mExp = memento.getGameExp();
}
public void play(int hp, int exp)
{
mHp = mHp - hp;
mExp = mExp + exp;
}
}
// Memento
public class GameMemento {
// 假設只有這兩個資料要保留
private int mGameHp;
private int mGameExp;
public GameMemento(int hp, int exp)
{
mGameHp = hp;
mGameExp = exp;
}
public int getGameHp()
{
return mGameHp;
}
public int getGameExp()
{
return mGameExp;
}
}
// Caretaker
public class GameCaretaker {
// 保留要處理的資料。
// 這邊只是範例,所以 Caretaker
// 只能處理一個 Memento。
// 實務上當然可以用更複雜的結構來
// 處理多個 Memento,如 ArrayList。
private GameMemento mMemento;
public GameMemento getMemento()
{
return mMemento;
}
public void setMemento(GameMemento memento)
{
mMemento = memento;
}
}
public class Demo {
public static void main(String[] args)
{
// 創造一個遊戲角色
GamePlayer player = new GamePlayer(100, 0);
// 先存個檔
GameCaretaker caretaker = new GameCaretaker();
caretaker.setMemento(player.seveToMemento());
// 不小心死掉啦
player.play(-100, 10);
// 重新讀取存檔,又是一尾活龍
player.restoreFromMemento(caretaker.getMemento());
}
}
参考:
网友评论