关于设计模式(Design Pattern),自从“四人帮”第一次在《Design Patterns: Elements of Reusable Object-Oriented Software》中将其上升到理论高度,发展到今天已经成为众所周知的代码设计经验的总结。然而,关于设计模式的具体使用,大多数人却望而生畏,具体原因在于:书上提及的理论往往过于晦涩,读者只见其结果,却不明白这样设计的动机与过程;即,缺乏大型项目实践的支撑,或者说,没有经历一个数十万行项目的迭代、开发、重构,确实难以理解设计模式的智慧。

  自然,笔者也不敢说有多懂设计模式,只是从一些开源的项目中看见些许设计模式的影子,本文打算不做过多的理论讲解,而是直接从Cocos2d-x工程入口的代码部分尝试与大家分享其中体现的代理模式。注:笔者使用的Cocos2d-x版本为2.2.6,不能保证3.X版本一样适用。

  先建立一个最简单的Hello World项目(具体过程不做阐述,网上可以查看教程),我们找到main函数,代码如下:

 int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine); // create the application instance
AppDelegate app;
CCEGLView* eglView = CCEGLView::sharedOpenGLView();
eglView->setViewName("Hello World");
eglView->setFrameSize(, );
return CCApplication::sharedApplication()->run();
}

  从 AppDelegate app; 我们看出这是一个代理模式,查看其定义我们看到 class AppDelegate : private cocos2d::CCApplication ,即继承自CCApplication类。我们先放在一边,继续往下看。

  显然,想要从main函数跳到工程的入口是从 CCApplication::sharedApplication()->run() 这句代码实现的。其中sharedApplication()是一个单例模式,其内部有一个静态指针,指针为空则创建对象,不为空则跳过,如此设定以保证多次调用仍然只返回唯一一个单例。当然本文不是讲解单例模式,简单提及一下。下面我们转入CCApplication的定义,找到如下代码:

     // Initialize instance and cocos2d.
if (!applicationDidFinishLaunching())
{
return ;
}

  显然,这里便是整个游戏工程的入口。我们考虑,该函数在何处定义?如果 applicationDidFinishLaunching() 是CCApplication类中的成员函数,我们便可以直接调用而无需顾虑。而事实是这样吗?我们转入其定义。看到 bool AppDelegate::applicationDidFinishLaunching() 这样的代码。即,真正的实现是在AppDelegate中完成的。然而,我们发现,在CCApplication类中既无定义,也无声明,那为什么可以使用?我们看CCApplication类,看到 class CC_DLL CCApplication : public CCApplicationProtocol 这句话,即它是继承子CCApplicationProtocol。再次跳转到该函数的定义,我们看到 virtual bool applicationDidFinishLaunching() = ; ,这是一个纯虚函数。何为纯虚函数?纯虚函数是一种特殊的虚函数,在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。在派生类中,若未对该接口进行复写(OverRide),该派生类依然为纯虚基类。显然,在CCApplication类中并没有进行复写,却可以直接调用该接口。

  回到最上面,我们知道AppDelegate继承自CCApplication类,在AppDelegate中给出了该函数的定义 virtual bool applicationDidFinishLaunching(); ,这不是一个纯虚函数,即,可以对其进行实现。

  回顾一下逻辑,整理如下:

 #if 0

 CCApplicationProtocol //Interface
virtual bool applicationDidFinishLaunching() = ; //定义一个纯虚函数的接口 //各个平台不同的逻辑
CCApplication: public CCApplicationProtocol
run()
{
applicationDidFinishLaunching(); //调用该接口
} AppDelegate: private CCApplication
applicationDidFinishLaunching() //实现接口
{
真正的入口;
} virtual bool applicationDidFinishLaunching(); virtual void applicationDidEnterBackground(); virtual void applicationWillEnterForeground(); #endif

  关于代理模式的优点:

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

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


由Cocos2d-x工程入口窥见代理模式的更多相关文章

  1. php设计模式之Proxy(代理模式)和Facade(外观)设计模式

    Proxy(代理模式)和Facade(外观)设计模式它们均为更复杂的功能提供抽象化的概念,但这两种实现抽象化的过程大不相同 Proxy案例中,所有的方法和成员变量都来自于目标对象,必要时,该代理能够对 ...

  2. 代理模式及其在spring与struts2中的体现

    代理模式 代理模式有三个角色组成: 1.抽象主题角色:声明了真实主题和代理主题的共同接口. 2.代理主题角色:内部包含对真实主题的引用,并且提供和真实主题角色相同的接口. 3.真实主题角色:定义真实的 ...

  3. Java设计模式:代理模式(一)

    问题的提出 现在生活中,常常在微信朋友圈里面看到代购的信息,你想在国外买什么,香港买什么,但是又懒得自己过去,于是常常委托别人帮忙买奶粉买那啥的.这类问题的缘由是因为客户和原产地没有直接的接触,所以需 ...

  4. Java设计模式:代理模式(二)

    承接上文 三.计数代理 计数代理的应用场景是:当客户程序需要在调用服务提供者对象的方法之前或之后执行日志或者计数等额外功能时,就可以用到技术代理模式.计数代理模式并不是把额外操作的代码直接添加到原服务 ...

  5. Docker Kubernetes Service 网络服务代理模式详解

    Docker Kubernetes  Service 网络服务代理模式详解 Service service是实现kubernetes网络通信的一个服务 主要功能:负载均衡.网络规则分布到具体pod 注 ...

  6. 结构型--代理模式(Proxy)

    一.代理模式是什么? 代理模式属于GOF23设计模式中结构型中的设计模式,通过代理对象来屏蔽(部分或者屏蔽)对真实对象的直接访问,下图为UML图: 在代理模式中组件包括:抽象角色接口.代理角色类.真实 ...

  7. 设计模式GOF23(结构型模式:代理模式,适配模式,桥接模式,组合模式,装饰模式,外观模式,享元模式)

    结构型模式: – 分类: • 适配器模式.代理模式.桥接模式.装饰模式.组合模式.外观模式.享元模式 – 核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题.   结构 ...

  8. Java的三种代理模式&完整源码分析

    Java的三种代理模式&完整源码分析 参考资料: 博客园-Java的三种代理模式 简书-JDK动态代理-超详细源码分析 [博客园-WeakCache缓存的实现机制](https://www.c ...

  9. 重学 Java 设计模式:实战代理模式「模拟mybatis-spring中定义DAO接口,使用代理类方式操作数据库原理实现场景」

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 难以跨越的瓶颈期,把你拿捏滴死死的! 编程开发学习过程中遇到的瓶颈期,往往是由于看不 ...

随机推荐

  1. 面向对象(this关键字)

    package com_package2; public class Person3 { private int age; private String name; public int getAge ...

  2. Advanced R之函数

    转载请注明出处,谢谢. 再次声明下,本人水平有些,错误之处敬请指正. 函数 函数是R基本的块结构单元:为了掌握本书中的更高级技术,你需要对函数有扎实的了解.也许你已经写过一些函数,并了解函数的基本知识 ...

  3. Programming With Objective-C---- Introduction ---- Objective-C 学习(一)

    About Objective-C Objective-C is the primary programming language you use when writing software for ...

  4. 《SpringBoot揭秘 快速构建微服务体系》读后感(二)

    最简单的springBoot应用 package com.louis.test; import org.springframework.boot.SpringApplication; import o ...

  5. day1 java基础回顾-IO流

    IO流的分类 注:这几个类都是抽象类. IO解决问题: 解决设备与设备之间 的数据传输问题. 比如: 硬盘--->内存 内存----->硬盘 字节流: 输入字节流:---------| I ...

  6. centos 安装webbench 用于web压力测试

    1.WebBench安装: yum install ctags(先安装依赖库) mkdir /usr/local/man (创建一个目录不然会报错) wget http://home.tiscali. ...

  7. 拓展kmp模板

    算法描述:设字符串T,长度为n,字符串S,长度为m.在线性时间内求出T的每一个后缀所对应S的最长前缀. 假设T=“AAAAB”,S="AAAA". //拓展KMP ; //字符串长 ...

  8. Keras实现CIFAR-10分类

      仅仅为了学习Keras的使用,使用一个四层的全连接网络对MNIST数据集进行分类,网络模型各层结点数为:3072: : 1024 : 512:10:   使用50000张图片进行训练,10000张 ...

  9. ue4 简单数据储存

  10. php curl采集,服务器gzip压缩返回数据怎么办

    一般服务器不会胡乱返回gzip压缩的数据,一般是客户端请求的头部里包含你浏览器能接受的压缩方式, Accept-Encoding:gzip,deflate,sdch   这里是gzip .deflat ...