由Cocos2d-x工程入口窥见代理模式

  关于设计模式(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++开发方向,欢迎私信或邮件联系。

 

你可能感兴趣的:(cocos2d-x)