由Cocos2d-x工程入口窥见代理模式
关于设计模式(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工程入口窥见代理模式的更多相关文章
- php设计模式之Proxy(代理模式)和Facade(外观)设计模式
Proxy(代理模式)和Facade(外观)设计模式它们均为更复杂的功能提供抽象化的概念,但这两种实现抽象化的过程大不相同 Proxy案例中,所有的方法和成员变量都来自于目标对象,必要时,该代理能够对 ...
- 代理模式及其在spring与struts2中的体现
代理模式 代理模式有三个角色组成: 1.抽象主题角色:声明了真实主题和代理主题的共同接口. 2.代理主题角色:内部包含对真实主题的引用,并且提供和真实主题角色相同的接口. 3.真实主题角色:定义真实的 ...
- Java设计模式:代理模式(一)
问题的提出 现在生活中,常常在微信朋友圈里面看到代购的信息,你想在国外买什么,香港买什么,但是又懒得自己过去,于是常常委托别人帮忙买奶粉买那啥的.这类问题的缘由是因为客户和原产地没有直接的接触,所以需 ...
- Java设计模式:代理模式(二)
承接上文 三.计数代理 计数代理的应用场景是:当客户程序需要在调用服务提供者对象的方法之前或之后执行日志或者计数等额外功能时,就可以用到技术代理模式.计数代理模式并不是把额外操作的代码直接添加到原服务 ...
- Docker Kubernetes Service 网络服务代理模式详解
Docker Kubernetes Service 网络服务代理模式详解 Service service是实现kubernetes网络通信的一个服务 主要功能:负载均衡.网络规则分布到具体pod 注 ...
- 结构型--代理模式(Proxy)
一.代理模式是什么? 代理模式属于GOF23设计模式中结构型中的设计模式,通过代理对象来屏蔽(部分或者屏蔽)对真实对象的直接访问,下图为UML图: 在代理模式中组件包括:抽象角色接口.代理角色类.真实 ...
- 设计模式GOF23(结构型模式:代理模式,适配模式,桥接模式,组合模式,装饰模式,外观模式,享元模式)
结构型模式: – 分类: • 适配器模式.代理模式.桥接模式.装饰模式.组合模式.外观模式.享元模式 – 核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题. 结构 ...
- Java的三种代理模式&完整源码分析
Java的三种代理模式&完整源码分析 参考资料: 博客园-Java的三种代理模式 简书-JDK动态代理-超详细源码分析 [博客园-WeakCache缓存的实现机制](https://www.c ...
- 重学 Java 设计模式:实战代理模式「模拟mybatis-spring中定义DAO接口,使用代理类方式操作数据库原理实现场景」
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 难以跨越的瓶颈期,把你拿捏滴死死的! 编程开发学习过程中遇到的瓶颈期,往往是由于看不 ...
随机推荐
- 构造函数参数new class[0]的作用
new Class[0];就是传一个长度为1的Class数组过去.内容为null. new Class[0]表示有零个元素的Class数组,即空数组,与传入null结果是一样的,都表示取得无参构造方法 ...
- Servlet拦截方式
Servlet拦截方式 1.拦截固定后缀的url,比如设置为 *.do.*.action, 例如:/user/add.action 此方法最简单,不会导致静态资源(jpg,js,css)被拦截. 2. ...
- TensorFlow中tf.ConfigProto()配置Sesion运算方式
博主个人网站:https://chenzhen.online tf.configProto用于在创建Session的时候配置Session的运算方式,即使用GPU运算或CPU运算: 1. tf.Con ...
- spring oauth2.0 实现原理
官方原文:http://projects.spring.io/spring-security-oauth/docs/oauth2.html 翻译及修改补充:Alex Liao. 转载请注明来源:htt ...
- Ubuntu下安装wine plsql
在电脑上安装了第二系统Ubuntu,但面临各种Linux不支持的开发软件也是束手无策.比如常用的Eclipse,PlSQl,Oracle,QQ等等,于是,上网查阅各种资料,最终的解决方案还是要依赖于w ...
- jsp学习与提高(一)——JSP生命周期、三大指令及动作
1.jsp定义: 1.1以java语言为脚本语言,运行在服务端的程序: 1.2处理客户请求,生成页面 1.3其本质是个sevlet会生成.java文件编译后再生成.class文件 2.jsp生命周期( ...
- Mac PyCharm2018破解
1.下载破解补丁 https://link.jianshu.com/?t=http%3A%2F%2Fidea.lanyus.com%2Fjar%2FJetbrainsCrack-2.7-release ...
- 条件分页 分页条件和页参数传递方式一 超链接拼串 方式二 使用查询表单searchForm
<%-- Created by IntelliJ IDEA. User: jie Date: 2019/5/10 Time: 20:00 To change this template use ...
- Jmeter集成Jira提交缺陷
笔者曾在文章<Jmeter排忧解难—生成excel结果文件>聊到了一种提高接口测试效率的方法.今天,咱们接着对“提高接口测试效率”这个话题做更深入的探讨.作为一名接口测试人员,我们是否一直 ...
- Python内建函数二
内置函数二: 1.lambda (匿名函数) 为了解决一些简答的需求而设计的一句话函数.不需要def来声明. def func(n): return n*n f = lambda n: n*n 注意: ...