設計模式之備忘錄模式

提高班14期郭倩_Ulrica發表於2018-06-05

前言

這個模式讓人感覺很人性化,很明顯是體現了物件導向思想。

備忘錄模式

英文:Memento

what

在不破壞封裝性的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。這樣以後就可將該物件恢復到原先儲存的狀態。

結構圖:

備忘錄

Originator:

可根據需要決定Memento儲存originator的哪些內部狀態。

備忘錄有兩個介面,caretaker只能看到備忘錄的窄介面,它只能將備忘錄傳遞給其他物件。originator能看到一個寬介面,允許它訪問返回到先前狀態所需的所以體驗資料。

Caretaker:

不能對備忘錄的內容進行操作或檢查。

場景

  1. 我們經常玩遊戲。有的遊戲走錯一步就可能滿盤皆輸,比如象棋。所以,為了人性化一些,裡面往往有一些“悔棋”功能,在這個時候我們就可以將“快要死了的棋局”起死回生,點選撤銷,恢復悔棋前的狀態。這時候就用到了備忘錄模式。
  2. 在比如說,我現在在寫部落格,但是這時候突然有事必須要關掉部落格,那麼我會先進行儲存,這樣等我回來時再開啟部落格,還是走之前的狀態,系統自動給我恢復到了原狀~

應用

比較適用於①功能比較複雜的,但②需要維護或記錄屬性歷史的類,或者③需要儲存的屬性只是眾多屬性中的一小部分時,originator可根據儲存的memento資訊還原到前一狀態。

作用:
當角色的狀態改變的時候,有可能這個狀態無效,這時候就可以使用暫時儲存起來的備忘錄將狀態復原了。

如果在某個系統中使用命令模式時,需要實現命令的撤銷功能,那麼命令模式(點我啊)可以使用備忘錄模式來儲存可撤銷操作的狀態。

程式碼錯誤

  1. 存在二義性:
    錯誤
  2. 執行時,提示“Process is terminated due to StackOverflowException.”程式已終止。錯誤列表顯示“從不使用欄位”
    欄位
    解決:

這裡的返回值應該是private裡面的。而不是public

private RoleStateMemento memento; //注意大小寫
        public RoleStateMemento Memento
        {
            get { return memento; }  //注意返回值
            set { memento = value; }
        }

程式碼展示

遊戲角色類:(originator類)

class GameRole//遊戲角色類:(originator類)
    {
        //生命力
        private int vit;
        public int Vitality
        {
            get { return vit; }
            set { vit = value; }
        }

        //攻擊力
        private int atk;
        public int Attack
        {
            get { return atk; }
            set { atk = value; }
        }

        //防禦力
        private int def;
        public int Defense
        {
            get { return def; }
            set { def = value; }
        }

        //狀態顯示
        public void StateDisplay()
        {
            Console.WriteLine("角色當前狀態:");
            Console.WriteLine("體力:{0}",this.vit );
            Console.WriteLine("攻擊力:{0}", this.atk );
            Console.WriteLine("防禦力:{0}", this.def );
            Console.WriteLine("");
        }

        //獲得初始狀態
        public void GetInitState()
        {
            this.vit = 100;
            this.atk = 100;
            this.def = 100;
        }
         //戰鬥
        public void Fight()
        {
            this.vit = 0;
            this.atk = 0;
            this.def = 0;
        }

        //儲存角色狀態
        public RoleStateMemento SaveState()
        {
            return (new RoleStateMemento (vit,atk,def ));
        }

        //恢復角色狀態
        public void RecoveryState(RoleStateMemento memento)
        {
            this.vit = memento .Vitality ;
            this.atk = memento .Attack ;
            this.def = memento.Defense;
        }


    }

角色狀態儲存箱類:(memento類)

class RoleStateMemento //角色狀態儲存箱類:(memento類)
    {
        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 Vitality
        {
            get { return vit; }
            set { vit = value; }
        }
         //攻擊力
        public int Attack
        {
            get { return atk ; }
            set { atk  = value; }
        }

        //防禦力
        public int Defense
        {
            get { return def ; }
            set { def = value; }
        }
    }

角色狀態管理者類:(caretaker類)

//角色狀態管理者類:(caretaker類)
    class RoleStateCaretaker
    {
        private RoleStateMemento memento; //注意大小寫
        public RoleStateMemento Memento
        {
            get { return memento; }  //注意返回值
            set { memento = value; }
        }
    }

客戶端程式碼:

static void Main(string[] args)
        {
            //大戰boss前,遊戲角色初始狀態,三項指標資料都是100

            GameRole monkey = new GameRole();
            monkey.GetInitState();
            monkey.StateDisplay();

            //儲存進度,由於封裝在memento中,因此我們並不知道儲存了哪些具體的角色資料。

            RoleStateCaretaker stateAdmin = new RoleStateCaretaker();
            stateAdmin.Memento = monkey.SaveState();

            //大戰boss時,損耗嚴重,三項指標資料都下降了,
            monkey.Fight();
            monkey.StateDisplay();

            //恢復之前狀態(但是我們可以復活呀),重新來過。

            monkey.RecoveryState(stateAdmin.Memento);
            monkey.StateDisplay();

            Console.Read();
        }
    }

效果展示:

備忘錄

後記

今天新增加了錯誤程式碼一列,希望可以幫到同樣受困的夥伴們~以後這一欄也是必不可少的功課,只有遇到錯誤才能更好的成長!

相關文章