1 引子
這是一個幸福的時代,特別是作為一個java程序員(感慨一下,java程序員確實比C/C++程序員幸福)。
基於我個人的一貫風格,我不准備采用大量技術術語和官腔講述這次的主題:工廠模式應用與發展。今時今日提到工廠模式,相信絕大部分的人都已經對這個詞匯有所了解(恩恩,注意我的用詞,我沒說“對他的概念、含義和用途有所了解”)。
那麼,在開始進入正題之前,我們先回顧一下工廠模式的作用(我不准備列舉在這,自己想想)。
OK,下面開始我的講述,請大家耐心點(是的,我怕有人半途而廢;噢,再啰嗦一下,重點在示例代碼)!
2 石器時代
2.1 痛苦的開始
據說原始人類所使用的工具的產生有很大的隨機性。例如這樣的情況:最開始大家吃肉肉,一窩蜂撲上去撕咬;後來可能覺得不衛生(也可能是覺得咬起來牙齒疼,也可能是覺得自己每次都咬不過別人),於是按自己牙齒的模樣,找些放大比例的動物牙齒(或者石頭),嘗試著割肉,發現挺好使的,於是工具產生了。
代碼界同樣有這樣的事情發生(產品的童鞋要我們為每個名人設計一句話):
...
if(strcmp(name, "billgates") == 0) {
printf("Doyou like Win8?");
} else if(strcmp(name, "Stevejobs") == 0) {
printf("sonice iPhone.");
} else if(strcmp(name, "Zuckerberg")== 0) {
printf("Welcometo facebook.");
} else {
...
看上去這樣沒有什麼不妥,是不是?
然而,事情遠遠沒有這麼簡單。
“花心”的產品童鞋總會給我們提點新要求,有木有?他們很可能覺得每個名人都應該充分體現自己的個性,要求為他們增加肢體語言什麼的。有木有?
好吧,我們的痛苦從此開始了……
2.2 夢想
我猜想,原始人類估計不像我們現在這麼貪婪,他們在尋找牙齒與石頭的時候,很可能是在想:老天爺,賜我一把割肉神器吧(而不是:老天爺,賜我一具不用吃飯的肉體吧)!當然,在得到神器的那一天來臨之前,我們的原始先祖們,還是不得不繼續尋找更鋒利的牙齒與石頭。
是的,代碼界也發生了一些變化:
...
void billgatesShowtime() {
printf("Do you like Win8?");
printf("Andput up his hands.");
}
...
if(strcmp(name, "billgates") == 0) {
BillgatesShowtime();
} else if(strcmp(name, "Stevejobs") == 0) {
StevejobsShowtime();
} else if(strcmp(name,"Zuckerberg") == 0) {
ZuckerbergShowtime();
} else {
...
噢,看上去確實好多了,我們可以讓老比爾給大家舉手示意了,不是嗎?
是的,你興奮了很久,甚至晚上睡覺都帶著醉人的笑容。
順便還做了個夢:你站在雲端,覺得孤獨,便心血來潮的說:要有比爾,於是比爾出現了;你又說:要有喬布斯,於是喬布斯出現了;你接著說:要有馬化騰……
3 青銅器時代
恩,或許在這之前,還要經歷一個後石器時代,在那個過程中,我們使用typedef定義函數指針,並建立名字與函數地址關聯的數組(或者map),使代碼變得更優雅;這確實是一個很大的改善,但仍然還不足以代表設計模式上的進步,所以我們忽視他的存在。
3.1 痛苦的持續
哦,時光悠悠,石器時代過去了。
我們的先祖仍在期待神器,仍在尋找更鋒利的割肉工具……
代碼界,你跌坐在屏幕前,嘴裡念念有詞:果然應驗了,我TM說“要有馬化騰”干毛啊?
是的,可惡的產品童鞋說了,要把馬化騰加入這個名人行列,同時還要抱一只企鵝。
在一萬只草泥馬奔騰過後,你從泥濘的草原上站起來,向著太陽的方向,前進前進前進進……
3.2 曙光
好在先祖們發現了青銅,相比之下,青銅比石頭和牙齒更靠譜,還能自己決定著割肉工具的外形(嚯嚯,越拉風越好哇)。
代碼界裡,你也在進步:
...
class CPeople {
virtualvoid showtime() = 0;
};
...
class CXiaomage : public CPeople {
voidshowtime() {
printf("Fuck360.");
printf("Doyou 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())
returniter->second;
returnNULL;
}
};
...
CFamousPersons famousPersons;
People* people = famousPersons.find(name);
if(people != NULL) {
people->showtime();
}
...
咦?代碼好像變多了,但我們為你自豪;因為這已經是一個完整的工廠模式的實現了。
是的,代碼可讀性增強了,邏輯結構也清晰了很多,對不對。關鍵是你再也不同擔心產品給你增加名人,不用擔心名人的各種性格和癖好。
於是你睡了個好覺,但你誠惶誠恐,不敢做夢。
4 鐵器時代
4.1 憤怒的燃燒
青銅的冶煉和鍛造技術已經達到了巅峰。吳鉤、魚腸、干將、莫邪……,喔噢,這已經是割肉神器了不?
仿佛從現在開始,擔心先祖的生活已經有點多余了。
是的,因為代碼界裡,名人的數量已經達到了10000+(名人的各種性格和癖好,也讓你震驚到了無以復加)。
你已無數次的被這份名單中人從夢中驚醒,你的生活開始變得枯燥,你的世界漸漸黑白。仿佛你的生活就是為了這份名單而存在(有的名人改名了;有的名人換公司了;有的名人變性了,擦啊啊啊……)。
CFamousPersons已經被神獸草泥馬踐踏了無數次,而且變成了工程裡面個頭最大的源代碼文件;每次你從peoples裡找名人的時候,這份超長的名單幾乎亮瞎了你的钛合金眼。
一次次的代碼更新,SVN上的代碼號直接蹦到了5位數;當你部署代碼時,看著運維冒著幽光的怨恨眼神,你叔忍了,但你嬸認為絕不能忍;於是你發糞圖牆……
4.2 福音
有一天,某位先祖發現自己的神器青銅大劍居然被一柄小匕首斬斷了,擦啊,這是什麼玩意?超神器?
呵呵,豬腳模式開啟了,在代碼界,你也發現了“神器”。
你先把這個名單弄到了數據庫裡(表名famous_persons):
然後,你用這把“神器”大刀闊斧把臃腫的CFamousPersons剁的稀爛。
再然後,你重造了一個輪子:
...
typedef void* (__stdcall*PExportClass)();
…
class CFamousPersons {
…
private:
CConnectionconn;
...
constchar* findPlugin(string name) {
char*pluginFile = "";
stringsqlCmd = "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();
returnpluginFile;
}
public:
CPeople*find(string name) {
CPeople*people = NULL;
stringpluginFile = findPlugin(name);
if(!pluginFile.empty()){
HMODULEplugin = LoadLibrary(pluginFile);
if(plugin){
PExportClassexportClass = (PExportClass)GetProcAddress(plugin, "exportClass");
if(exportClass)
people = (CPeople*)exportClass();
}
}
returnpeople;
}
};
...
哇噢,酷!從此,你遠離了CFamousPersons;遠離了那糟糕的日子。生活貌似從這一刻又重新燃起了希望……
嗯,出乎意料的,你又做夢了,在夢裡,你拋棄了數據庫,增加了好些個輔助模塊,代碼簡潔而優雅,充滿美感……
5 蒸汽機時代
5.1 貪婪的欲望
終於,當我們的先祖們還沉浸在冷兵器時代,突如其來的炮火,把國門轟得稀爛;戰火不斷,黃金白銀都頂不住火藥的貪婪……
代碼界裡,你也終究沒來得及親自嘗試拋棄數據庫的喜悅,各種框架猝不及防的降臨。
5.2 神賜
好吧,時間線已經很接近現實,不過先祖們始終沒有得到神賜,一切都靠自力更生。
代碼界裡不一樣,我們有了很多框架(神器)。比如說COM(恩,還有個學模學樣的跨平台的XPCOM)。說起COM(應算是業界如雷灌招風耳的大神器了),聽上去好像不是很沾邊,但COM的CreateInstance其實現原理和應用機制,仍然是工廠模式。
當然,實現形式有了很大變化,就如他不采用名字,而是采用GUID映射;他不用數據庫,而是使用注冊表保存映射關系;他甚至還有自己的內存機制;有自己的數據類型等等。(廣告:預知詳情,請關注後續分享)。
6 另一個夢想