創(chuàng)建型模式的使用
GOF94的創(chuàng)建型模式,總共有五種。其中一種的范圍是類的,四種是對象的。
1.Factory Method(virtual constructor)。
工廠方法在創(chuàng)建型模式里面的使用的頻率是很高的,也是非常容易使用的。
由于工廠方法本身的一些特點(diǎn),它們往往被說明成為靜態(tài)的,如果這個(gè)靜態(tài)函數(shù)就是待創(chuàng)建的類型的靜態(tài)成員函數(shù),那么,這就是Meyer所謂的
virtual constructor。(More Effective C++)這個(gè)東東很是厲害,我們可以利用它,依據(jù)數(shù)據(jù)創(chuàng)建正確的對象。
在游戲的過程中,存檔和取檔是在所難免的。在存儲的過程中,你需要將一個(gè)自定義類串行化到文件中。這個(gè)到不是什么難事。但是如果你要從文件中讀取對象呢?
首先你就需要知道這個(gè)對象的類,然后才能創(chuàng)建啊。這個(gè)時(shí)候,virtual constructor便可以顯示出它的作用來。什么?你知道了?好,你寫一
段代碼給我看看。
TypeID id;//類標(biāo)識,每個(gè)類唯一,可以籍此判斷類型
switch (id)
{
case NPC_ID :
//創(chuàng)建NPC,讀入數(shù)據(jù)。。。
case MONSTOR: 

}
不不不,我絕對不是叫你要這么寫!這段代碼的代價(jià)太大了。有效率的做法是,我們使用一個(gè)映射表。方法不是靜態(tài)的嗎?那好,我就給它統(tǒng)一一個(gè)函數(shù)聲明:
typedef (void*)(*PFnCreateObject)(ByteStream& stream/*資源流*/);
注意,這后面的這個(gè)void*理論上是需要返回一個(gè)指針,而這個(gè)指針又因?yàn)轭愋娃D(zhuǎn)換而失去了識別類型的作用。但是不要忘了,我們調(diào)用的是一個(gè)函數(shù),一切需要彌補(bǔ)的缺陷,都可以在函數(shù)中完成。
因此,我們可以這樣寫一個(gè)查找表:
PFnCreateObject creatorFuncTable[MAX_TYPE_ID];
在程序需要讀取存檔的時(shí)候,我們可以:
void Load(ByteStream& stream)
{
//
TypeID id;
stream.Read(&id);
(*creatorFuncTable[id])(stream);
//
}
這種做法的麻煩之處在于要為每一個(gè)類開一個(gè)ID。如果是手工完成這一項(xiàng)的話,是很需要點(diǎn)功夫的。而且維護(hù)起來也不是很方便。因此,這里可以用GUID再HASH的辦法獲取一個(gè)Hash表。保存對象時(shí)要保存相應(yīng)的GUID,查找時(shí)使用Hash查找。
順便說一下,如果有個(gè)非虛函數(shù) Foo,有個(gè)類
class A
{
void foo() {
if(this == NULL) {
//操作,但是不能調(diào)用A類的非靜態(tài)成員或虛函數(shù)
cout << "Aha! 還是能運(yùn)行哦!" << endl;
} else {
cout << "沒什么了不起的,地球人都知道!" << endl;
}
}
};
//
A* p = NULL;
p->foo();
這個(gè)調(diào)用是正確的!因?yàn)槌耸褂肊CX傳入NULL(this)以外,并沒有非法的內(nèi)存操作。因此,運(yùn)行時(shí)也不會(huì)有錯(cuò)誤。 當(dāng)然,以上的調(diào)用實(shí)際上是不可取的。而且當(dāng)foo為虛函數(shù)的時(shí)候,這種調(diào)用就不能正確進(jìn)行了,因?yàn)樘摵瘮?shù)是先要訪問虛函數(shù)表的,而虛函數(shù)表又是對象而不是類的一部分,調(diào)用了就訪問了錯(cuò)誤的地址,所以其行為是不確定的。
所以說,F(xiàn)actory Method 的特點(diǎn)就是:依據(jù)不同條件,創(chuàng)造不同型別。(這里的條件就是煩人的類型ID)在創(chuàng)建之前,我們不能確定物體的型別。
如果我們將靜態(tài)函數(shù)變?yōu)橐粋€(gè)類(不是被創(chuàng)建的類)的成員函數(shù),那么,這個(gè)結(jié)構(gòu)就和Gof94上的描述一樣了。Gof94上的
Factory Method,有著它自己的特點(diǎn),這一點(diǎn)請參見書本。這里與Gof94的帶繼承的工廠方法相比,只是說對于不同的創(chuàng)建條件,構(gòu)造函數(shù)的分
派方式不同而已。(這點(diǎn)我將在下面講述到)
通過對工廠方法的使用,我們可以實(shí)現(xiàn)很多的功能,例如利用池分配等等。其中的一些功能,我們也可以通過重載operator new和
operator delete的辦法實(shí)現(xiàn),但是一些其它的功能,這種方法實(shí)現(xiàn)起來就會(huì)很吃力或者不可行,那么,工廠方法就為我們在創(chuàng)建的時(shí)候便搭建了一
個(gè)足夠我們恣意施展才華的場所。