1      引子

這是一個幸福的時代,特別是作為一個java程序員(感慨一下,java程序員確實比C/C++程序員幸福)。

基于我個人的一貫風(fēng)格,我不準(zhǔn)備采用大量技術(shù)術(shù)語和官腔講述這次的主題:工廠模式應(yīng)用與發(fā)展。今時今日提到工廠模式,相信絕大部分的人都已經(jīng)對這個詞匯有所了解(恩恩,注意我的用詞,我沒說“對他的概念、含義和用途有所了解”)。

那么,在開始進(jìn)入正題之前,我們先回顧一下工廠模式的作用(我不準(zhǔn)備列舉在這,自己想想)。

OK,下面開始我的講述,請大家耐心點(是的,我怕有人半途而廢;噢,再啰嗦一下,重點在示例代碼)!

2      石器時代

2.1    痛苦的開始

據(jù)說原始人類所使用的工具的產(chǎn)生有很大的隨機(jī)性。例如這樣的情況:最開始大家吃肉肉,一窩蜂撲上去撕咬;后來可能覺得不衛(wèi)生(也可能是覺得咬起來牙齒疼,也可能是覺得自己每次都咬不過別人),于是按自己牙齒的模樣,找些放大比例的動物牙齒(或者石頭),嘗試著割肉,發(fā)現(xiàn)挺好使的,于是工具產(chǎn)生了。

代碼界同樣有這樣的事情發(fā)生(產(chǎn)品的童鞋要我們?yōu)槊總€名人設(shè)計一句話):

...

if(strcmp(name, "bill gates") == 0) {

       printf("Do you like Win8?");

} else if(strcmp(name, "Steve jobs") == 0) {

       printf("so nice iPhone.");

} else if(strcmp(name, "Zuckerberg") == 0) {

       printf("Welcome to facebook.");

} else {

...

看上去這樣沒有什么不妥,是不是?

然而,事情遠(yuǎn)遠(yuǎn)沒有這么簡單。

“花心”的產(chǎn)品童鞋總會給我們提點新要求,有木有?他們很可能覺得每個名人都應(yīng)該充分體現(xiàn)自己的個性,要求為他們增加肢體語言什么的。有木有?

好吧,我們的痛苦從此開始了……

2.2    夢想

我猜想,原始人類估計不像我們現(xiàn)在這么貪婪,他們在尋找牙齒與石頭的時候,很可能是在想:老天爺,賜我一把割肉神器吧(而不是:老天爺,賜我一具不用吃飯的肉體吧)!當(dāng)然,在得到神器的那一天來臨之前,我們的原始先祖?zhèn)儯€是不得不繼續(xù)尋找更鋒利的牙齒與石頭。

是的,代碼界也發(fā)生了一些變化:

...

void billgatesShowtime() {

       printf ("Do you like Win8?");

       printf("And put up his hands.");

}

...

if(strcmp(name, "bill gates") == 0) {

       BillgatesShowtime();

} else if(strcmp(name, "Steve jobs") == 0) {

       StevejobsShowtime();

} else if(strcmp(name, "Zuckerberg") == 0) {

       ZuckerbergShowtime();

} else {

...

噢,看上去確實好多了,我們可以讓老比爾給大家舉手示意了,不是嗎?

是的,你興奮了很久,甚至晚上睡覺都帶著醉人的笑容。

順便還做了個夢:你站在云端,覺得孤獨,便心血來潮的說:要有比爾,于是比爾出現(xiàn)了;你又說:要有喬布斯,于是喬布斯出現(xiàn)了;你接著說:要有馬化騰……

3      青銅器時代

恩,或許在這之前,還要經(jīng)歷一個后石器時代,在那個過程中,我們使用typedef定義函數(shù)指針,并建立名字與函數(shù)地址關(guān)聯(lián)的數(shù)組(或者map),使代碼變得更優(yōu)雅;這確實是一個很大的改善,但仍然還不足以代表設(shè)計模式上的進(jìn)步,所以我們忽視他的存在。

3.1    痛苦的持續(xù)

哦,時光悠悠,石器時代過去了。

我們的先祖仍在期待神器,仍在尋找更鋒利的割肉工具……

代碼界,你跌坐在屏幕前,嘴里念念有詞:果然應(yīng)驗了,我TM說“要有馬化騰”干毛啊?

是的,可惡的產(chǎn)品童鞋說了,要把馬化騰加入這個名人行列,同時還要抱一只企鵝。

在一萬只草泥馬奔騰過后,你從泥濘的草原上站起來,向著太陽的方向,前進(jìn)前進(jìn)前進(jìn)進(jìn)……

3.2    曙光

好在先祖?zhèn)儼l(fā)現(xiàn)了青銅,相比之下,青銅比石頭和牙齒更靠譜,還能自己決定著割肉工具的外形(嚯嚯,越拉風(fēng)越好哇)。

代碼界里,你也在進(jìn)步:

...

class CPeople {

       virtual void showtime() = 0;

};

...

class CXiaomage : public CPeople {

       void showtime() {

              printf("Fuck 360.");

              printf("Do you like QQ pets?");

       }

};

...

class CFamousPersons {

private:

map<string, CPeople*> peoples;

 

public:

CFamousPersons() {

              peoples.insert(pair<string, CPeople*>("bill gates", new CBillgates()));

              peoples.insert(pair<string, CPeople*>("steve jobs", new CStevejobs()));

              peoples.insert(pair<string, CPeople*>("馬化騰", new CXiaomage()));

              …

       }

 

       People* find(string name) {

              map<string, CPeople*>::iterator iter = peoples.find(name);

              if(iter != peoples.end())

                     return iter->second;

              return NULL;

       }

};

...

CFamousPersons famousPersons;

People* people = famousPersons.find(name);

 

if(people != NULL) {

       people->showtime();

}

...

咦?代碼好像變多了,但我們?yōu)槟阕院溃灰驗檫@已經(jīng)是一個完整的工廠模式的實現(xiàn)了。

是的,代碼可讀性增強了,邏輯結(jié)構(gòu)也清晰了很多,對不對。關(guān)鍵是你再也不同擔(dān)心產(chǎn)品給你增加名人,不用擔(dān)心名人的各種性格和癖好。

于是你睡了個好覺,但你誠惶誠恐,不敢做夢。

4      鐵器時代

4.1    憤怒的燃燒

青銅的冶煉和鍛造技術(shù)已經(jīng)達(dá)到了巔峰。吳鉤、魚腸、干將、莫邪……,喔噢,這已經(jīng)是割肉神器了不?

仿佛從現(xiàn)在開始,擔(dān)心先祖的生活已經(jīng)有點多余了。

是的,因為代碼界里,名人的數(shù)量已經(jīng)達(dá)到了10000+(名人的各種性格和癖好,也讓你震驚到了無以復(fù)加)。

你已無數(shù)次的被這份名單中人從夢中驚醒,你的生活開始變得枯燥,你的世界漸漸黑白。仿佛你的生活就是為了這份名單而存在(有的名人改名了;有的名人換公司了;有的名人變性了,擦啊啊啊……)。

CFamousPersons已經(jīng)被神獸草泥馬踐踏了無數(shù)次,而且變成了工程里面?zhèn)€頭最大的源代碼文件;每次你從peoples里找名人的時候,這份超長的名單幾乎亮瞎了你的鈦合金眼。

一次次的代碼更新,SVN上的代碼號直接蹦到了5位數(shù);當(dāng)你部署代碼時,看著運維冒著幽光的怨恨眼神,你叔忍了,但你嬸認(rèn)為絕不能忍;于是你發(fā)糞圖墻……

4.2    福音

有一天,某位先祖發(fā)現(xiàn)自己的神器青銅大劍居然被一柄小匕首斬斷了,擦啊,這是什么玩意?超神器?

呵呵,豬腳模式開啟了,在代碼界,你也發(fā)現(xiàn)了“神器”。

你先把這個名單弄到了數(shù)據(jù)庫里(表名famous_persons):


然后,你用這把“神器”大刀闊斧把臃腫的CFamousPersons剁的稀爛。

再然后,你重造了一個輪子:

...

typedef void* (__stdcall *PExportClass)();

class CFamousPersons {

private:

CConnection conn;

...

       const char* findPlugin(string name) {

              char* pluginFile = "";

              string sqlCmd = "SELECT * FROM famous_persons WHERE Name=\"";

sqlCmd += name;

sqlCmd += "\"";

              CRecordset* rs = conn.executeQuery(sqlCmd);

 

              if(!(rs->Eof() || rs->Bof())) {

pluginFile = new char[256];

strncpy(pluginFile, rs->fieldValue(2), 256);

              }

 

              rs->destroy();

 

              return pluginFile;

       }

 

public:

CPeople* find(string name) {

              CPeople* people = NULL;

              string pluginFile = findPlugin(name);

 

              if(!pluginFile.empty()) {

                     HMODULE plugin = LoadLibrary(pluginFile);

                     if(plugin) {

                            PExportClass exportClass = (PExportClass)GetProcAddress(plugin, "exportClass");

                            if(exportClass)

                                   people = (CPeople*)exportClass();

                     }

              }

 

              return people;

       }

};

...

哇噢,酷!從此,你遠(yuǎn)離了CFamousPersons;遠(yuǎn)離了那糟糕的日子。生活貌似從這一刻又重新燃起了希望……

嗯,出乎意料的,你又做夢了,在夢里,你拋棄了數(shù)據(jù)庫,增加了好些個輔助模塊,代碼簡潔而優(yōu)雅,充滿美感……

5      蒸汽機(jī)時代

5.1    貪婪的欲望

終于,當(dāng)我們的先祖?zhèn)冞€沉浸在冷兵器時代,突如其來的炮火,把國門轟得稀爛;戰(zhàn)火不斷,黃金白銀都頂不住火藥的貪婪……

代碼界里,你也終究沒來得及親自嘗試拋棄數(shù)據(jù)庫的喜悅,各種框架猝不及防的降臨。

5.2    神賜

好吧,時間線已經(jīng)很接近現(xiàn)實,不過先祖?zhèn)兪冀K沒有得到神賜,一切都靠自力更生。

代碼界里不一樣,我們有了很多框架(神器)。比如說COM(恩,還有個學(xué)模學(xué)樣的跨平臺的XPCOM)。說起COM(應(yīng)算是業(yè)界如雷灌招風(fēng)耳的大神器了),聽上去好像不是很沾邊,但COMCreateInstance其實現(xiàn)原理和應(yīng)用機(jī)制,仍然是工廠模式。

當(dāng)然,實現(xiàn)形式有了很大變化,就如他不采用名字,而是采用GUID映射;他不用數(shù)據(jù)庫,而是使用注冊表保存映射關(guān)系;他甚至還有自己的內(nèi)存機(jī)制;有自己的數(shù)據(jù)類型等等。(廣告:預(yù)知詳情,請關(guān)注后續(xù)分享)。

6      另一個夢想

……