• 由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

      关于代理模式的优点:

    • 职责清晰,真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
    • 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了的作用和保护了目标对象的作用。
    • 高扩展性

      好了,本文到此就要结束了,通过一个具体的工程案例,希望大家对代理模式能学到一些新的内容。关于理论部分就不多做阐述,大家可以去看看《设计模式》这本书。


  • 相关阅读:
    8款超好用的SVG编辑工具用起来
    连接数据后,当执行查询语句报错:ORA-01219: 数据库未打开: 仅允许在固定表/视图中查询
    idea注册码
    chrome 打开本地 pdf 会自动开启下载
    exp/imp 注释乱码问题或Oracle EXP-00091的解决方法
    帆软报表 异常汇总及方案.
    Intellij IDEA的Facets和Artifacts
    Diamond types are not supported at language level '5‘
    IDEA Error:java: Compilation failed: internal java compiler error
    IdentityServer Topics(5)- 使用第三方登录
  • 原文地址:https://www.cnblogs.com/huashu/p/4446997.html
Copyright © 2020-2023  润新知