• <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>

            歲月流轉,往昔空明

            C++博客 首頁 新隨筆 聯系 聚合 管理
              118 Posts :: 3 Stories :: 413 Comments :: 0 Trackbacks
            創建型模式的使用
            GOF94的創建型模式,總共有五種。其中一種的范圍是類的,四種是對象的。
            1.Factory Method(virtual constructor)。
            工廠方法在創建型模式里面的使用的頻率是很高的,也是非常容易使用的。
            由于工廠方法本身的一些特點,它們往往被說明成為靜態的,如果這個靜態函數就是待創建的類型的靜態成員函數,那么,這就是Meyer所謂的 virtual constructor。(More Effective C++)這個東東很是厲害,我們可以利用它,依據數據創建正確的對象。
            在游戲的過程中,存檔和取檔是在所難免的。在存儲的過程中,你需要將一個自定義類串行化到文件中。這個到不是什么難事。但是如果你要從文件中讀取對象呢? 首先你就需要知道這個對象的類,然后才能創建啊。這個時候,virtual constructor便可以顯示出它的作用來。什么?你知道了?好,你寫一 段代碼給我看看。

            TypeID id;//類標識,每個類唯一,可以籍此判斷類型
            switch (id)
            {
            case NPC_ID : 
            //創建NPC,讀入數據。。。
            case MONSTOR: 

            }

            不不不,我絕對不是叫你要這么寫!這段代碼的代價太大了。有效率的做法是,我們使用一個映射表。方法不是靜態的嗎?那好,我就給它統一一個函數聲明:
            typedef (void*)(*PFnCreateObject)(ByteStream& stream/*資源流*/);
            注意,這后面的這個void*理論上是需要返回一個指針,而這個指針又因為類型轉換而失去了識別類型的作用。但是不要忘了,我們調用的是一個函數,一切需要彌補的缺陷,都可以在函數中完成。
            因此,我們可以這樣寫一個查找表:
            PFnCreateObject creatorFuncTable[MAX_TYPE_ID];
            在程序需要讀取存檔的時候,我們可以:
            void Load(ByteStream& stream)
            {
              
            //
              TypeID id;
              stream.Read(
            &id);
              (
            *creatorFuncTable[id])(stream);
              
            //
            }
            這種做法的麻煩之處在于要為每一個類開一個ID。如果是手工完成這一項的話,是很需要點功夫的。而且維護起來也不是很方便。因此,這里可以用GUID再HASH的辦法獲取一個Hash表。保存對象時要保存相應的GUID,查找時使用Hash查找。
            順便說一下,如果有個非虛函數 Foo,有個類
            class A
            {
              
            void foo() {
                
            if(this == NULL) {
                  
            //操作,但是不能調用A類的非靜態成員或虛函數
                  cout << "Aha! 還是能運行哦!" << endl;
                } 
            else {
                  cout 
            << "沒什么了不起的,地球人都知道!" << endl;
                }
              }
            };
            //
            A* p = NULL;
            p
            ->foo(); 

             這個調用是正確的!因為除了使用ECX傳入NULL(this)以外,并沒有非法的內存操作。因此,運行時也不會有錯誤。 當然,以上的調用實際上是不可取的。而且當foo為虛函數的時候,這種調用就不能正確進行了,因為虛函數是先要訪問虛函數表的,而虛函數表又是對象而不是類的一部分,調用了就訪問了錯誤的地址,所以其行為是不確定的。
            所以說,Factory Method 的特點就是:依據不同條件,創造不同型別。(這里的條件就是煩人的類型ID)在創建之前,我們不能確定物體的型別。
            如果我們將靜態函數變為一個類(不是被創建的類)的成員函數,那么,這個結構就和Gof94上的描述一樣了。Gof94上的 Factory Method,有著它自己的特點,這一點請參見書本。這里與Gof94的帶繼承的工廠方法相比,只是說對于不同的創建條件,構造函數的分 派方式不同而已。(這點我將在下面講述到)
            通過對工廠方法的使用,我們可以實現很多的功能,例如利用池分配等等。其中的一些功能,我們也可以通過重載operator new和 operator delete的辦法實現,但是一些其它的功能,這種方法實現起來就會很吃力或者不可行,那么,工廠方法就為我們在創建的時候便搭建了一 個足夠我們恣意施展才華的場所。
            posted on 2007-06-07 17:45 空明流轉 閱讀(982) 評論(3)  編輯 收藏 引用

            評論

            # re: 亂彈游戲中的設計模式 - Factory Method 2007-06-07 21:46 李錦俊
            I Like 設計模式~~
            多寫寫類似的文章哦。
            我還有好多個設計模式還沒有理解啊。  回復  更多評論
              

            # re: 亂彈游戲中的設計模式 - Factory Method 2007-06-07 22:19 pass86
            估計PFnCreateObject creatorFuncTable[MAX_TYPE_ID];因該是
            PFnCreateObject* creatorFuncTable[MAX_TYPE_ID];  回復  更多評論
              

            # re: 亂彈游戲中的設計模式 - Factory Method 2007-06-07 23:25 空明流轉
            沒有錯,呵呵.  回復  更多評論
              

            免费久久人人爽人人爽av| 精品久久久久久国产潘金莲| 久久精品无码免费不卡| 午夜精品久久久内射近拍高清 | 伊人久久大香线蕉亚洲| 久久精品国产亚洲av麻豆小说| 久久精品国产一区| 要久久爱在线免费观看| 久久精品夜夜夜夜夜久久| 久久国产视屏| 国产精品免费看久久久| 久久久久久久综合狠狠综合| 精品久久久久久中文字幕| 精品一二三区久久aaa片| 91精品国产色综久久| 亚洲日本va中文字幕久久| 国产叼嘿久久精品久久| 久久综合给合久久国产免费| 亚洲精品WWW久久久久久| 99久久成人18免费网站| 久久久久久国产精品免费无码| 老司机午夜网站国内精品久久久久久久久 | 久久精品国产亚洲av高清漫画 | 青青热久久综合网伊人| 久久精品人人槡人妻人人玩AV| 国产成人精品久久亚洲高清不卡| 新狼窝色AV性久久久久久| 亚洲精品tv久久久久久久久久| 国内精品久久久久影院网站| 久久亚洲精品视频| 99国内精品久久久久久久| 国产精品久久久久久久久| 日日噜噜夜夜狠狠久久丁香五月| 狠狠精品久久久无码中文字幕 | 国内精品欧美久久精品| 久久精品成人免费看| 97r久久精品国产99国产精| 久久国产色AV免费观看| 亚洲欧美伊人久久综合一区二区| 亚洲va中文字幕无码久久不卡| 亚洲日本va中文字幕久久|