美文网首页
设计模式四:备忘录模式(Memento Pattern)

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

作者: _浅墨_ | 来源:发表于2019-01-30 23:39 被阅读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)

    相关文章

      网友评论

          本文标题:设计模式四:备忘录模式(Memento Pattern)

          本文链接:https://www.haomeiwen.com/subject/xffvjqtx.html