• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            積木

            No sub title

              C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
              140 Posts :: 1 Stories :: 11 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(1)

            我參與的團隊

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            轉載自:http://patmusing.blog.163.com/blog/static/13583496020101501825958/


            Aka. Token

            在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存其狀態這樣以后就可以將該對象恢復到原先保存的狀態。

            “Without violating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later.” – GoF

            動機

            有時候需要記錄一個對象的內部狀態。比如要實現checkpoint或者undo這樣的機制,可以讓使用者從臨時性的操作跳出來或者需要修復錯誤的時候,你必須將狀態信息保存在某個地方,以便在進行某些操作后,將對象恢復到原來的狀態。但通常情況下,對象封裝了狀態(即私有成員變量),因此其他的對象無法訪問這些狀態,而且也不可能將這些狀態保存在對象之外。如果將這些狀態設置成公有的,又會違反面向對象封裝性的原則,同時也會削弱應用的可靠性和可擴展性。

            在軟件構建過程中, 某些對象的狀態在轉換過程中,可能由于某種需要,要求程序能夠回溯到對象之前處于某個時刻的狀態。如果使用一些共有接口來讓其他對象得到對象的狀態,便會暴露對象的細節實現。Memento設計模式就可以實現對象狀態的良好保存與恢復,但同時又不會因此而破壞對象本身的封裝性。

            UML類圖:

            21. C++實現Behavioral - Memento模式 - 玄機逸士 - 玄機逸士博客

            角色

            - Memento

            1. 保存Originator對象的內部狀態。

            2. Originator外,其他對象均不能訪問Memento對象。

            - Originator

            1. 創建一個包含其當前內部狀態快照的Memento對象。

            2. 使用Memento對象來恢復其內部狀態。

            - Caretaker

            1. Memento對象的容器。在C++中一般用stack來實現。

            2. 從不對Memento對象的內容進行檢查或操作。

            示例代碼:

            // Memento.h

            #include <iostream>

            #include <stack>

            using namespace std;

            // CMemento類,用來保存CRectangle的狀態

            class CMemento

            {

            private: // 所有的成員變量和成員函數都是私有的

            int topx; // 因此除友元類CRectangle外,其他對象都無法訪問

            int topy;

            int width;

            int height;

            private:

            CMemento()

            {

            }

            //private: // 1. 如果編寫了顯式拷貝構造函數,那么,它必須是公有的,

            // CMemento(const CMemento& memo) // 否則CMementoStack將無法調用該拷貝構造函數。

            // { // 2. 如果沒有顯式的拷貝構造函數,那么缺省的拷貝構造函數總是公有的。

            // topx = memo.topx; // 3. Memento模式中,如果僅考慮保存一次狀態,則

            // topy = memo.topy; // CMementoStack是不必要的,那么拷貝構造函數,可以

            // width = memo.width; // 顯式地聲明為private的,盡管在CRectanglecreate_memento

            // height = memo.height; // 成員函數中也會調用CMemento的拷貝構造函數,但CRectangle

            // } // CMemento的友元類,因此不存在這方面的限制。

            private:

            void set_state(int topx, int topy, int width, int height) // 保存CRectangle的狀態

            {

            this->topx = topx;

            this->topy = topy;

            this->width = width;

            this->height = height;

            }

            friend class CRectangle; // 友元類CRectangle,可以訪問CMemento中的所有內容

            };

            // CRectangle類。一個矩形,需要保存狀態改變的類

            class CRectangle

            {

            private:

            int topx; // 矩形左上角的x坐標

            int topy; // 矩形左上角的y坐標

            int width; // 矩形的寬

            int height; // 矩形的高

            public:

            CRectangle(int topx, int topy, int width, int height):topx(topx), topy(topy), width(width), height(height)

            {

            }

            // 模擬移動矩形的位置到指定的點,即改變了矩形的狀態

            void move_to(int topx, int topy)

            {

            this->topx = topx;

            this->topy = topy;

            }

            // 模擬改變矩形的長和寬,即改變了矩形的狀態

            void change_width_height(int width, int height)

            {

            this->width = width;

            this->height = height;

            }

            // 將矩形恢復到memo中所保存的狀態

            void set_memento(CMemento memo)

            {

            this->topx = memo.topx;

            this->topy = memo.topy;

            this->width = memo.width;

            this->height = memo.height;

            }

            // 將矩形的狀態保存到一個CMemento對象

            CMemento create_memento()

            {

            CMemento cm;

            cm.set_state(this->topx, this->topy, this->width, this->height);

            return cm;

            }

            // 輸出矩形的狀態信息

            void print_info()

            {

            cout << "Top left point's x coordinate: " << topx << endl;

            cout << "Top left point's y coordinate: " << topy << endl;

            cout << "The width is: " << width << endl;

            cout << "The height is: " << height << endl;

            }

            };

            // CMemento對象的容器,可以用來保存多個CMemento對象,通常用stack來實現

            class CMementoStack

            {

            private:

            stack<CMemento> stk;

            public:

            void add_memento(CMemento memo)

            {

            stk.push(memo); //CMemento對象壓入棧中

            }

            CMemento get_memento()

            {

            CMemento cm = stk.top(); // 取得CMemento對象。這個過程會用到CMemento類的拷貝構造函數,

            // 由于CMemento對象中的成員變量均是普通類型(非指針、非類對象)

            // 因此使用默認的拷貝構造函數即可

            stk.pop(); // 刪除已經取得的CMemento對象

            return cm;

            }

            };

            // Memento.cpp

            #include "Memento.h"

            int main(int argc, char **argv)

            {

            CRectangle cr(10, 10, 100, 100);

            CMementoStack cs;

            cout << "Initial states: " << endl;

            cr.print_info();

            CMemento cm0 = cr.create_memento(); // 將狀態保存到CMemento對象

            cs.add_memento(cm0); // CMemento對象壓棧

            // 第一次改變狀態

            cr.change_width_height(200, 200); // 改變矩形的高度和寬度

            cr.move_to(20, 20); // 改變矩形的位置

            cout << "\nAfter 1st states changed: " << endl;

            cr.print_info();

            CMemento cm1 = cr.create_memento(); // 將狀態保存到CMemento對象

            cs.add_memento(cm1); // CMemento對象壓棧

            // 第二次改變狀態

            cr.change_width_height(300, 300); // 改變矩形的高度和寬度

            cr.move_to(30, 30); // 改變矩形的位置

            cout << "\nAfter 2nd states changed: " << endl;

            cr.print_info();

            // ... 這里不再壓棧

            // 恢復到第一次狀態的改變

            cr.set_memento(cs.get_memento());

            cout << "\nStates restored to 1st change: " << endl;

            cr.print_info();

            // 恢復到初始狀態

            cr.set_memento(cs.get_memento());

            cout << "\nStates restored to initial: " << endl;

            cr.print_info();

            }

            運行結果:

            Initial states:

            Top left point's x coordinate: 10

            Top left point's y coordinate: 10

            The width is: 100

            The height is: 100

            After 1st states changed:

            Top left point's x coordinate: 20

            Top left point's y coordinate: 20

            The width is: 200

            The height is: 200

            After 2nd states changed:

            Top left point's x coordinate: 30

            Top left point's y coordinate: 30

            The width is: 300

            The height is: 300

            States restored to 1st change:

            Top left point's x coordinate: 20

            Top left point's y coordinate: 20

            The width is: 200

            The height is: 200

            States restored to initial:

            Top left point's x coordinate: 10

            Top left point's y coordinate: 10

            The width is: 100

            The height is: 100

            結果符合預期。

            補充說明:

            1. 未設置其成員變量為public的前提下,在對象的外部保存一個其狀態,頗需技巧,而且用不同語言來實現的時候也有所不同。

            a. 對于C++,通常使用友元類來實現。

            b. 對于C#,使用internal關鍵字。

            c. 對于Java,使用package protected訪問控制。

            與其處于相同包中的子類,和處于相同包中的其它類均可以訪問pakcage protected的對象或變量。

            Java中的訪問權限有public,private,protected和默認的包訪問權限,如果類中的屬性方法沒有顯示的指明訪問權

            限,則具有包訪問權限,很多人也稱它為friendly訪問權限,也有人稱為packeged權限,而packagedfriendly

            這兩個關鍵字在實際中都是不存在的。在Java中,訪問權限修飾符權限從高到低是publicprotectedpackage

            protectedprivate

            d. C++, C#Java均可使用內部類的方式來實現類似的功能,不過對于“將狀態存儲于對象之外”而言,稍嫌勉強。

            2. 關于拷貝構造函數,請看:http://patmusing.blog.163.com/blog/static/1358349602009113061024796/

            3. 關于友元類,請看:http://patmusing.blog.163.com/blog/static/1358349602010182331153/



            posted on 2013-03-08 14:51 Jacc.Kim 閱讀(206) 評論(0)  編輯 收藏 引用 所屬分類: 設計模式
            久久精品中文字幕大胸| 久久国产色AV免费看| 婷婷国产天堂久久综合五月| 久久AV高潮AV无码AV| 精品久久久久久国产潘金莲| 精品久久人人妻人人做精品| 久久狠狠爱亚洲综合影院| 成人国内精品久久久久影院| 久久亚洲天堂| 国产精品视频久久| 国产精品亚洲综合久久| 狠狠色丁香婷婷久久综合不卡| 久久久久综合中文字幕| 精品无码久久久久国产| 欧美亚洲另类久久综合婷婷| 日韩AV无码久久一区二区| 久久久久国产精品麻豆AR影院 | 久久只有这里有精品4| 青青草原综合久久| 久久水蜜桃亚洲av无码精品麻豆| 久久av免费天堂小草播放| 99久久国产热无码精品免费| 久久午夜免费视频| 国产成人无码精品久久久免费 | 久久精品国产精品亚洲毛片| 一级做a爰片久久毛片毛片| 国产精品免费久久久久久久久| 国产精品久久久久国产A级| 99久久国产精品免费一区二区| 久久久久久一区国产精品| 欧美一区二区精品久久| 久久久久人妻精品一区二区三区| 欧美激情一区二区久久久| 亚洲Av无码国产情品久久| 国产午夜精品久久久久九九电影| 国产精品福利一区二区久久| 久久国产亚洲高清观看| 精品综合久久久久久888蜜芽| 久久发布国产伦子伦精品| 国产成人无码久久久精品一| 国产精品无码久久久久久|