關於設計模式(Design Pattern),自從“四人幫”第一次在《Design Patterns: Elements of Reusable Object-Oriented Software》中將其上升到理論高度,發展到今天已經成為眾所周知的代碼設計經驗的總結。然而,關於設計模式的具體使用,大多數人卻望而生畏,具體原因在於:書上提及的理論往往過於晦澀,讀者只見其結果,卻不明白這樣設計的動機與過程;即,缺乏大型項目實踐的支撐,或者說,沒有經歷一個數十萬行項目的迭代、開發、重構,確實難以理解設計模式的智慧。
自然,筆者也不敢說有多懂設計模式,只是從一些開源的項目中看見些許設計模式的影子,本文打算不做過多的理論講解,而是直接從Cocos2d-x工程入口的代碼部分嘗試與大家分享其中體現的代理模式。注:筆者使用的Cocos2d-x版本為2.2.6,不能保證3.X版本一樣適用。
先建立一個最簡單的Hello World項目(具體過程不做闡述,網上可以查看教程),我們找到main函數,代碼如下:
1 int APIENTRY _tWinMain(HINSTANCE hInstance, 2 HINSTANCE hPrevInstance, 3 LPTSTR lpCmdLine, 4 int nCmdShow) 5 { 6 UNREFERENCED_PARAMETER(hPrevInstance); 7 UNREFERENCED_PARAMETER(lpCmdLine); 8 9 // create the application instance 10 AppDelegate app; 11 CCEGLView* eglView = CCEGLView::sharedOpenGLView(); 12 eglView->setViewName("Hello World"); 13 eglView->setFrameSize(480, 320); 14 return CCApplication::sharedApplication()->run(); 15 }
從 AppDelegate app; 我們看出這是一個代理模式,查看其定義我們看到 class AppDelegate : private cocos2d::CCApplication ,即繼承自CCApplication類。我們先放在一邊,繼續往下看。
顯然,想要從main函數跳到工程的入口是從 CCApplication::sharedApplication()->run() 這句代碼實現的。其中sharedApplication()是一個單例模式,其內部有一個靜態指針,指針為空則創建對象,不為空則跳過,如此設定以保證多次調用仍然只返回唯一一個單例。當然本文不是講解單例模式,簡單提及一下。下面我們轉入CCApplication的定義,找到如下代碼:
1 // Initialize instance and cocos2d. 2 if (!applicationDidFinishLaunching()) 3 { 4 return 0; 5 }
顯然,這裡便是整個游戲工程的入口。我們考慮,該函數在何處定義?如果 applicationDidFinishLaunching() 是CCApplication類中的成員函數,我們便可以直接調用而無需顧慮。而事實是這樣嗎?我們轉入其定義。看到 bool AppDelegate::applicationDidFinishLaunching() 這樣的代碼。即,真正的實現是在AppDelegate中完成的。然而,我們發現,在CCApplication類中既無定義,也無聲明,那為什麼可以使用?我們看CCApplication類,看到 class CC_DLL CCApplication : public CCApplicationProtocol 這句話,即它是繼承子CCApplicationProtocol。再次跳轉到該函數的定義,我們看到 virtual bool applicationDidFinishLaunching() = 0; ,這是一個純虛函數。何為純虛函數?純虛函數是一種特殊的虛函數,在許多情況下,在基類中不能對虛函數給出有意義的實現,而把它聲明為純虛函數,它的實現留給該基類的派生類去做。在派生類中,若未對該接口進行復寫(OverRide),該派生類依然為純虛基類。顯然,在CCApplication類中並沒有進行復寫,卻可以直接調用該接口。
回到最上面,我們知道AppDelegate繼承自CCApplication類,在AppDelegate中給出了該函數的定義 virtual bool applicationDidFinishLaunching(); ,這不是一個純虛函數,即,可以對其進行實現。
回顧一下邏輯,整理如下:
1 #if 0
8 CCApplicationProtocol //Interface 9 virtual bool applicationDidFinishLaunching() = 0; //定義一個純虛函數的接口 10 11 //各個平台不同的邏輯 12 CCApplication: public CCApplicationProtocol 13 run() 14 { 15 applicationDidFinishLaunching(); //調用該接口 16 } 17 18 AppDelegate: private CCApplication 19 applicationDidFinishLaunching() //實現接口 20 { 21 真正的入口; 22 } 23 24 virtual bool applicationDidFinishLaunching(); 25 26 virtual void applicationDidEnterBackground(); 27 28 virtual void applicationWillEnterForeground(); 29 30 #endif
關於代理模式的優點:
好了,本文到此就要結束了,通過一個具體的工程案例,希望大家對代理模式能學到一些新的內容。關於理論部分就不多做闡述,大家可以去看看《設計模式》這本書。
注:本文系筆者原創,歡迎轉載,但請注明筆者及出處。另,筆者目前於哈工大計算機學院大四在讀,正在找工作,求職意願為C++開發方向,歡迎私信或郵件聯系。