设计模式四:备忘录模式(Memento Pattern)

2019-01-30  本文已影响39人  _浅墨_
备忘录模式(Memento Pattern)

保存一个对象的某个状态,以便在适当的时候恢复它的这个状态。有时需要在某个时刻捕获对象的内部状态,并且能够在稍后恢复到该状态。 这种情况在操作出错时很有用, 像具有撤销操作的计算器场景。

Memento 模式使用三个 actor 类:Originator 在 Memento 对象中创建和存储状态;Memento 包含要恢复的对象的状态; Caretaker 对象负责从 Memento 恢复对象状态。

意图:

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样可以在以后将对象恢复到原先保存的状态。

何时使用:

记录一个对象的内部状态,目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态。比如绘图过程的撤销操作。

应用示例:
  1. Windows 里的 ctri + z。
  2. IE 中的后退。
  3. 数据库的事务管理。
    etc...
如何解决:

通过一个备忘录类专门存储对象状态。

关键代码:

客户不与备忘录类(Memento)耦合,与备忘录管理类(Caretaker)耦合。

优点:
  1. 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史状态。
  2. 实现了信息的封装,使得用户不需要关心状态的保存细节。
缺点:

消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。

如果 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());
    }
}

参考:

  1. 备忘录模式
  2. Memento design pattern
  3. 備忘錄模式 (Memento Pattern)
上一篇下一篇

猜你喜欢

热点阅读