本文由子龙山人原创,泰然授权转载;

原文链接:http://www.zilongshanren.com/cocos2d-x-design-pattern2-two-stage-create/

乍一看标题,大家可能会觉得很奇怪,神马是“二段构建模式”呢?

所谓二段构建,就是指创建对象时不是直接通过构建函数来分配内存并完成初始化操作。取而代之的是,构造函数只负责分配内存,而初始化的工作则由一些名为initXXX的成员方法来完成。然后再定义一些静态类方法把这两个阶段组合起来,完成最终对象的构建。因为在《Cocoa设计模式》一书中,把此惯用法称之为“Two Stage Creation”,即“二段构建”。因为此模式在cocos2d里面被广泛使用,所以把该模式也引入过来了。

1.应用场景:
二段构建在cocos2d-x里面随处可见,自从2.0版本以后,所有的二段构建方法的签名都改成create了。这样做的好处是一方面统一接口,方便记忆,另一方面是以前的类似Cocoa的命名规范不适用c++,容易引起歧义。下面以CCSprite为类,来具体阐述二段构建的过程,请看下列代码:

//此方法现在已经不推荐使用了,将来可能会删除
CCSprite* CCSprite::spriteWithFile(const char *pszFileName)
{return CCSprite::create(pszFileName);
}CCSprite* CCSprite::create(const char *pszFileName)
{CCSprite *pobSprite = new CCSprite();  //1.第一阶段,分配内存if (pobSprite && pobSprite->initWithFile(pszFileName))  //2.第二阶段,初始化{pobSprite->autorelease();  //!!!额外做了内存管理的工作。return pobSprite;}CC_SAFE_DELETE(pobSprite);return NULL;
}

如上面代码中的注释所示,创建一个sprite明显被分为两个步骤:1.使用new来创建内存;2.使用initXXX方法来完成初始化。
因为CCSprite的构造函数也有初始化的功能,所以,我们再来看看CCSprite的构建函数实现:

CCSprite::CCSprite(void)
: m_pobTexture(NULL)
, m_bShouldBeHidden(false)
{}

很明显,这个构建函数所做的初始化工作非常有限,仅仅是在初始化列表里面初始化了m_pobTexture和m_bShouldBeHidden两个变量。实际的初始化工作大部分都放在initXXX系列方法中,大家可以动手去查看源代码。

2.分析为什么要使用此模式?
这种二段构建对于C++程序员来说,其实有点别扭。因为c++的构造函数在设计之初就是用来分配内存+初始化对象的。如果再搞个二段构建,实则是多此一举。但是,在objective-c里面是没有构造函数这一说的,所以,在Cocoa的编程世界里,二段构建被广泛采用。而cocos2d-x当初是从cocos2d-iphone移植过来了,为了保持最大限度的代码一致性,所以保留了这种二段构建方式。这样可以方便移植cocos2d-iphone的游戏,同时也方便cocos2d-iphone的程序员快速上手cocos2d-x。

不过在后来,由于c++天生不具备oc那种可以指定每一个参数的名称的能力,所以,cocos2d-x的设计者决定使用c++的函数重载来解决这个问题。这也是后来为什么2.0版本以后,都使用create函数的重载版本了。

虽然接口签名改掉了,但是本质并没有变化,还是使用的二段构建。二段构建并没有什么不好,只是更加突出了对象需要初始化。在某种程度上也可以说是一种设计强化。因为忘记初始化是一切莫名其妙的bug的罪魁祸首。同时,二段构建出来的对象都是autorelease的对象,而autorelease对象是使用引用计数来管理内存的。客户端程序员在使用此接口创建对象的时候,无需关心具体实现细节,只要知道使用create方法可以创建并初始化一个自动释放内存的对象即可。

在一点,在《Effective Java》一书中,也有提到。为每一个类提供一个静态工厂方法来代替构造函数,它有以下三个优点:
1.与构造函数不同,静态方法有名字,而构造函数只能通过参数重载。
2.它每次被调用的时候,不一定都创建一个新的对象。比如Boolean.valueOf(boolean)。
3.它还可以返回原类型的子类型对象。

因此,使用二段构建的原因有二:
1.兼容性、历史遗留原因。(这也再次印证了一句话,一切系统都是遗留系统,呵呵)
2.二段构建有其自身独有的优势。

3.使用此模式的优缺点是什么?
优点:
1.显示分开内存分配和初始化阶段,让初始化地位突出。因为程序员一般不会忘记分配内存,但却常常忽略初始化的作用。
2.见上面分析《Effective Java》的第1条:“为每一个类提供一个静态工厂方法来代替构造函数”
3.除了完成对象构建,还可以管理对象内存。
缺点:
1.不如直接使用构造函数来得直白、明了,违反直觉,但这个是相对的。

4.此模式的定义及一般实现
定义:
将一个对象的构建分为两个步骤来进行:1.分配内存 2.初始化
它的一般实现如下:

class Test
{public://静态工厂方法static Test* create(){Test *pTest = new Test;if (pTest && pTest->init()) {//这里还可以做其它操作,比如cocos2d-x里面管理内存return pTest;}return NULL;}//Test(){//分配成员变量的内存,但不初始化}bool init(){//这里初始化对象成员return true;}
private://这里定义数据成员};

5.在游戏开发中如何运用此模式
这个也非常简单,就是今后在使用cocos2d-x的时候,如果你继承CCSprite实现自定义的精灵,你也需要按照“二段构建”的方式,为你的类提供一个静态工厂方法,同时编写相应的初始化方法。当然,命名规范最好和cocos2d-x统一,即静态工厂方法为create,而初始化方法为initXXXX。

6.此模式经常与哪些模式配合使用
由于此模式在GoF的设计模式中并未出现,所以暂时不讨论与其它模式的关系。

最后看看cocos2d-x创始人王哲对于为什么要设计成二段构建的看法:
“其实我们设计二段构造时首先考虑其优势而非兼容cocos2d-iphone. 初始化时会遇到图片资源不存在等异常,而C++构造函数无返回值,只能用try-catch来处理异常,启用try-catch会使编译后二进制文件大不少,故需要init返回bool值。Symbian, Bada SDK,objc的alloc + init也都是二阶段构造”。

Cocos2D-x设计模式发掘之二:二段构建模式 -----------cocos2d-x3.0正式版本(7.22)相关推荐

  1. 二十三种设计模式(第十二种)-----代理模式(Proxy)

    二十三种设计模式(第十二种)-----代理模式(Proxy) 尚硅谷视频连接https://www.bilibili.com/video/BV1G4411c7N4?from=search&se ...

  2. Java设计模式(十二) 策略模式

    策略模式介绍 策略模式定义 策略模式(Strategy Pattern),将各种算法封装到具体的类中,作为一个抽象策略类的子类,使得它们可以互换.客户端可以自行决定使用哪种算法. 策略模式类图 策略模 ...

  3. UG二次开发教程(基于NX12.0/VS2015版本)

    ** UG二次开发教程(基于NX12.0/VS2015版本) 安装教程 ** UG NX12.0安装 NX12.0 安装包下载地址: 链接:https://pan.baidu.com/s/1I0CCF ...

  4. PDMS二次开发产品Naki.CI(二):升级到1.0.1版本

    目录 1.概述 2.升级功能介绍 3.GPART元件特性 4.GPART应用场景 5.下载地址 1.概述 1.0.1版本重点增加了GPART功能,GPART功能是CI的一个重要功能,使得编码的应用得到 ...

  5. 【专题系列】搞定设计模式之—— 十二 :代理模式

    点击上方"java大数据修炼之道",选择"设为星标" 优质文章, 第一时间送达 来源 | https://www.cnblogs.com/three-fight ...

  6. 设计模式之十二:组合模式(composite)

    GoF:它的意图是将对象组合成树形结构以表示"部分-整体"的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 组合模式解耦了客户程序与复杂元素内部结构,从 ...

  7. 设计模式笔记之二工厂方法模式

    工厂方法模式 为什么引入工厂方法模式? 当我们需要创建多个实例的时候,而这些类又是有着公共的方法,区别就是实现的具体操作不同,我们需要专门为这些类创建实例,但是,如果我们没有创建这些的类的权限的时候, ...

  8. 小话设计模式(番外二)委托模式

    委托(Delegate)模式定义了对象之间的一对一的关系,被委托方可以作为委托方的事件接收者或者数据源(Data Source),当它作为事件接受者的时候,可以认为它是一种特殊的观察者(参考小话设计模 ...

  9. 【白话设计模式二】外观模式(Facade)

    为什么80%的码农都做不了架构师?>>>    #0 系列目录# 白话设计模式 工厂模式 单例模式 [白话设计模式一]简单工厂模式(Simple Factory) [白话设计模式二] ...

  10. 子慕谈设计模式系列(二)——设计模式六大原则

    六大原则 单一职责原则 里氏替换原则 依赖倒置原则 接口隔离原则 迪米特法则 开闭原则 前言 设计模式不容易用文字描述清楚,而过多的代码,看起来也让人摸不到头脑,加上词语或者文字描述的抽象感,很容易让 ...

最新文章

  1. 奇葩错误:不同变量名称相同
  2. php微信分享时好时坏,手机端微信分享前几天都是正常的今天发现分享出去就不正常了设置,迅睿CMS,CodeIgniter技术文档,PHP开发文档,迅睿CMS框架官方教程...
  3. C++类静态成员与类静态成员函数
  4. linux+mysql+导出备份_Linux系统MySQL备份的导入导出的具体分析
  5. linux嵌入式物联网_嵌入式Linux如何加速物联网发展
  6. LiteOS:剖析时间管理模块源代码
  7. 我用Python抓取了【S11全球总决赛】直播评论,EDG nb
  8. CentOS7版本下载地址发布 附正确下载CentOS各个版本镜像
  9. 单片机与触摸屏通信c语言,讲述如何实现单片机与触摸屏的通信
  10. img loading=“lazy“ 是什么意思?
  11. linux命令里的xz是干嘛的,Ubuntu中的xz命令使用
  12. 华为人工智能atlasA800-9000物理服务器离线安装及CANN安装和MindSpore安装和Tensorflow安装
  13. c语言命令笔记本电脑快捷键,实用的电脑操作技巧(附快捷键)
  14. Different tests were collected between gw0 and gw1. The difference is: --- gw0
  15. Linux lvm(pv、vg、lv)操作命令收集
  16. Linux下用rar压缩和解压文件
  17. PEGA(Low-Code App Builder)Describing a data object
  18. 树莓派开发系列教程5——树莓派常用软件及服务(vi、远程桌面、ssh、samba、u盘)
  19. [蓝桥杯][2019年第十届真题]-----外卖店优先级
  20. 生化实验好帮手——牛血清白蛋白粉末,诊断级

热门文章

  1. C语言中的数据类型及输出格式
  2. 中文字体的FontMetrics解析
  3. Linux下破解UE
  4. python-jieba库
  5. 微信 8.0 「裂开」「炸弹」的特效代码
  6. 2022-2027年中国智能硬件行业市场深度分析及发展战略规划报告
  7. 用python分析世界各国的 “幸福指数”。
  8. 华三交换机配置access命令_华3交换机配置命令大全
  9. 静态路由的配置(以华为eNSP为例)
  10. 支付宝支付提示 4006 ISV权限不足