`
mmdev
  • 浏览: 12892887 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

【木头Cocos2d-x 018】面向接口编程01: 向她表白之实现函数回调

 
阅读更多

【在Cocos2d-x中面向接口编程01】向她表白之实现函数回调

首先,我要郑重地声明一件事情:我现在很尿急,但是厕所有人~

嗯,然后,我本来是一名Java程序员,由于Cocos2d-x太吸引人,我就硬着头皮学,可是C++Java那看似差不多,实际又确实差很多的纠结,让我变得...很尿急~

旁白:可以少说一些废话么?

最近我在试着写一个小游戏,叫做《粒子格斗》。

旁白:你已经说过了。。。

然后,我自己写了一个消息派发的功能,因为当时我并不知道Cocos2d-x已经集成了这个功能。我写Java习惯了,所以我按照Java的思维习惯实现了这个消息派发。如果对消息派发不熟悉或者完全不懂的朋友,那个,还是百度一下会好一些~

旁白:等等~!你不是应该介绍实现函数回调吗?

哦,对,我应该介绍实现函数回调的,但是如果你和我一样,是Java出身的,并且Java功底也不是很深厚,对于掌握新语言不太迅速的话,那么,请继续往下看。

如果你对C++已经是比较熟悉了,那,可以忽略这篇文章。

笨木头花心贡献,啥?花心?不呢,是用心~

转载请注明,原文地址
http://blog.csdn.net/musicvs/article/details/8261147

正文:

1.Java移植过来的消息派发

按照Java的思路,实现如下:

a.首先要实现消息派发的核心类,用于订阅、删除以及发布消息,这个类只需用实现3个函数:

/* 订阅消息 */
addListener(I_MessageDispath msgListener,  const char* sMsgType);

/* 删除订阅的消息 */
delListener(I_MessageDispath msgListener,  const char* sMsgType);

/* 发布消息 */
dispatchMsg(const char* sMsgType, CCObject* pData);


b.然后就要实现一个接口,一个代表消息订阅者的接口(这很美妙,我太喜欢接口了,它让我的代码之间的耦合度减小了很多很多~!),我们命名为I_MessageDispatch

class I_MessageDispatch : public CCObject {
public:    
    void onRecv(CCObject* pData);
};


c.详细的就不多解释了,我们再用一个CCDictionary保存不同类型的订阅者对象,比较完整的头文件内容如下:

class MessageDispatch : public CCObject {
public:
    static MessageDispatch* sharedMessageDispatch();

    /* 订阅消息 */
    addListener(I_MessageDispath msgListener,  const char* sMsgType);

    /* 删除订阅的消息 */
    delListener(I_MessageDispath msgListener,  const char* sMsgType);

    /* 发布消息 */
    dispatchMsg(const char* sMsgType, CCObject* pData);

private:
    /* CCDictionary<CCArray<I_MessageDispatch*>, const char*> */
    CCDictionary* mListenerDict;
};


d.然后就是一些细节的处理,好,不多说。就是字典里保存了消息类型和消息订阅者列表的对应关系。添加订阅的时候,就把实现了I_MessageDispatch接口的对象添加到对应的列表里(删除同理),然后发布消息的时候,取出要发布的消息类型对应的订阅者列表,对列表中的每个对象都调用一次onRecv函数,就可以了。

旁白:你不是说不多说么?==我感觉你说了很多

2.看起来它工作得很好

看起来,这个消息派发类工作得不错,所有功能都能正常运行。可是,问题来了。

C++中是没有接口的说法的,它只有多继承,我太怕多继承了,我可给它整晕了好多次。首先它有一个弱点,二义性,额,我就不解释了,专业解释请百度一下(旁白:你压根儿就解释不了吧...)。比如我有这样一个类:

class ClientFight : public CCLayer {
public:
    bool initWithLayer(CCLayer* mLayer);
    static ClientFight* createWithScene(CCLayer* mLayer);
#endif

嗯,看起来没有什么问题,但是,如果我这个类想订阅消息,怎么办?很简单啊,让它继承I_Messagedispatch接口,然后实现onRecv函数,然后订阅消息,就OK了,这是我在写Java时最容易想到的方法。

class ClientFight : public CCLayer, public I_MessageDispatch {
public:
    bool initWithLayer(CCLayer* mLayer);
  static ClientFight* createWithScene(CCLayer* mLayer);

    virtual void onRecv(CCObject* pData);
#endif


3.二义性,烦死你

来看看这样一个情景,某个类创建了ClientFight对象,并且保持了它的引用,当我要释放引用的时候,很自然要调用release函数。于是,编译器会告诉你,ClientFightrelease函数调用不明确。

原因呢?ClientFight继承了CCLayer,CCLayer继承了CCObjectI_MessageDispatch也继承了CCObject

于是,它们两个都有release函数,而ClientFight作为它们的子类,不知道该继承谁的release才好,所以编译器晕了,我也晕了。

要解决这个问题很简单,本来是这样调用的:mClientFight->release();

现在改为:mClientFight->CCLayer::release();

OK,这样编译器就不会晕了。但我还是晕啊,这太麻烦了~!这只是其中一个小问题,以后还会遇到更多问题,对于Java出身的人来说,我暂时无法接受这么麻烦的编码。

4.发现使用接口的新方式

我写的那个消息派发还不止这点故障,还有更多的故障,我就不说了。

偶然的机会,我百度了一下:Cocos2d-x观察者。

然后被我发现了子龙山人的博客,他介绍了Cocos2d-x的观察者模式,正好就是说的消息派发,木了个头的,原来已经有这个功能了,我还干嘛写得这么辛苦?

旁白:你废话多,所以总是干些多余的事情==

这个消息派发的功能大家可以看看这个类:CCNotificationCenter

或者看看大牛的博客:

http://www.zilongshanren.com/cocos2d-x-design-pattern-6-observer/

http://www.xinze.me/cocos2d-x-ccnotificationcenter/

我稍微拜读了一下Cocos2d-x的源码,发了一个很奇妙的地方,是一种“另类”的接口使用方式。

CCNotificationCenter在添加订阅者的时候,不需要订阅者实现某个接口,直接添加就可以了。

CCNotificationCenter会自动新建一个对象,这个对象是CCNotificationObserver,其实这就可以当做是一个接口,只不过订阅者不是实现这个接口,而是直接绑定到这个接口身上。按照我朋友的一个说法,这有点像适配器模式,也许就是适配器模式。

void CCNotificationCenter::addObserver(CCObject *target, 
                                       SEL_CallFuncO selector,
                                       const char *name,
                                       CCObject *obj)
{
    if (this->observerExisted(target, name))
        return;
    
    CCNotificationObserver *observer = new CCNotificationObserver(target, selector, name, obj);
    if (!observer)
        return;
    
    observer->autorelease();
    m_observers->addObject(observer);
}


怎么样?这样我们就可以避免一个对象为了订阅消息而不得不使用多继承了~

5.实例:向她表白

我们先来练练手,熟悉一下C++的函数参数的传递,再次声明,已经熟悉C++的朋友,直接忽略我。

旁白:我们早就忽略你了。。。

我们来实现一个经典的事情:我不敢向喜欢的女生表达,所以我想让我的朋友帮我这个忙。

这个类很简单:

#ifndef __TELL_LIKE_HER_H__
#define __TELL_LIKE_HER_H__

#include "cocos2d.h"

USING_NS_CC;

typedef void (CCObject::*SEL_CallFuncL) (CCObject*);
#define callfuncL_selector(_SELECTOR) (SEL_CallFuncL)(&_SELECTOR)

/* 这是一个不太像接口的接口 */
class I_LikeHer : public CCObject {
public:
    I_LikeHer(CCObject* targer, SEL_CallFuncL selector);

    void performSelector();

private:
    SEL_CallFuncL mSelector;
    CCObject* mTargert;
};

/* 这是我的朋友,他会帮我表达我的心意 */
class TellLikeHer : public CCObject {
public:
    static TellLikeHer* sharedTellLikeHer();

    /* 设置要表白的主角~ */
    void setTheActor(CCObject* targer, SEL_CallFuncL selector);

    /* 她就在这里,TellLikeHer将代替主角传达心意 */
    void sheIsHere();

private:
    static TellLikeHer* mTellLikeHer;

    I_LikeHer* mLikerHer;
};
#endif


要实现函数回调,我们需要两样东西:

typedefvoid(CCObject::*SEL_CallFuncL)(CCObject*);

#definecallfuncL_selector(_SELECTOR)(SEL_CallFuncL)(&_SELECTOR)

定义一个SEL_CallFuncL类型,以及一个传递函数参数的宏,我不太善于解释这个,我是依葫芦画瓢仿照源码写的,所以我选择不解释。

我们看到有一个I_LikeHer类,这个就是相当于一个接口,TellLikeHer类只保存这种接口的类,所以,我们依旧是面向接口编程,减少了耦合度。

我们来看看setTheActor函数(函数名取得不好,不要灭了我。。。):

void TellLikeHer::setTheActor( CCObject* targer, SEL_CallFuncL selector ) {
    mLikerHer = new I_LikeHer(targer, selector);
}


很简单,外部传进来的可以是任意的对象类型(当然,必须是继承了CCObject的),TellLikeHer类根据就不需要关心谁传进来了,因为它会创建一个I_LikeHer对象,把传进来的对象包装起来。

噗,听起来又有点像装饰者模式?是蛮像的。

再来看看sheIsHere函数:

void TellLikeHer::sheIsHere() {
    mLikerHer->performSelector();
}


这确实是在面向接口编程,因为我们只需要调用I_LikeHer接口的performSelector函数,调用了这个函数之后,监听者就会被回调,是的,我们帮他传达了心意了,并且告诉了他结果。

void I_LikeHer::performSelector() {
    (mTargert->*mSelector)(NULL);
}


这个是什么东西?它就是我们的主题:函数的回调。

这有点混乱,我明白。(旁白:你真心觉得只有一点点混乱?)我们来画图理解:

这很好地解决了二义性的问题。

也许是我的经验太少,对接口的使用了解不深入,所以总以为面向接口编程,就是定义一个接口,让其他类来实现。

Java里,我暂时没有遇到什么大问题。

不过在Cocos2d-x中刚好暴露了这种方式的缺陷。

好吧,对我来说,这是一次不错的收获。因为二义性的问题,让我认识了Cocos2d-x的消息派发(CCNotificationCenter)以及一种很不错接口使用方式。

又不过,这种接口的使用方式也不见得是万能的,如果一个接口要实现多个函数,那,又该怎么做呢?于是,我得拿出一本C++的教程,研究一下C++关于接口方面的知识了。

旁白:噗,说了等于没说。

分享到:
评论

相关推荐

    Cocos2d-x实战:JS卷——Cocos2d-JS开发

    资源名称:Cocos2d-x实战:JS卷——Cocos2d-JS开发内容简介:本书是介绍Cocos2d-x游戏编程和开发技术书籍,介绍了使用Cocos2d-JS中核心类、瓦片地图、物理引擎、音乐音效、数据持久化、网络通信、性能优化、多平台...

    cocos2d-x-2.1.5

    cocos2d-x-2.1.5

    cocos2d-x事件类

    在使用cocos2d-x开发游戏的过程中,为了实现逻辑和显示相分离。 在下通宵了一个晚上,写出了该事件类。 谨记,该事件只能用于cocos2d-x中。 事件发送者需要继承EventDispatcher类 事件接收者需要继承EventHandle类...

    大富翁手机游戏开发实战基于Cocos2d-x3.2引擎

    资源名称:大富翁手机游戏开发实战基于Cocos2d-x3.2引擎内容简介:李德国编著的《大富翁手机游戏开发实战(基于 Cocos2d-x3.2引擎)》使用Cocos2d-x游戏引擎技术,带领读者一步一步从零开始进行大富翁移动游戏的开发...

    Cocos2d-x高级开发教程

    Cocos2d-x是移动跨平台开发最流行的游戏引擎,而本书是一本很全面的、比较‘接地气’的游戏开发教程。书中汇聚了热门手机游戏《捕鱼达人》开发的实战经验,作者从最基础的内容开始,逐步深入地介绍了Cocos2d-x的相关...

    Cocos2d-x游戏编程——C++篇 .iso

    Cocos2d-x游戏编程——C++篇(电子工业出版社,徐飞 著)书本配套的光盘代码,

    cocos2d-x-3.2旧版引擎下载

    cocos2d-x-3.2下载,不多说。或者可以下载另一个资源 cocos引擎老版本集合(cocos2d-x-2.2.1 - 3.5) http://download.csdn.net/download/crazymagicdc/9982656

    cocos2d-x实战项目

    cocos2d-x实战项目 01.cocos2d-x原理及环境配置.rar 03.cocostudio使用方法及UI控制.rar 04.XML文件读取与骨骼动画.rarcocos2d-x实战项目 01.cocos2d-x原理及环境配置.rar 03.cocostudio使用方法及UI控制.rar 04.XML...

    Cocos2D-X游戏开发技术精解

    资源名称:Cocos2D-X游戏开发技术精解内容简介:Cocos2D-X是一款支持多平台的 2D手机游戏引擎,支持iOS、Android、BlackBerry等众多平台。当前,很多移动平台流行的游戏,都是基于Cocos2D-X开发的。 《Cocos2D-X...

    Cocos2d-x实战 JS卷

    Cocos2d-x实战

    cocos2d-x-3.0 类图

    这是我重新弄的cocos2d-x-3.0的类图.之前别人兄台弄的,有些不全面,有些地方错误.我这个可以说是最新的了.每个类添加了中文的详细注解,同时也添加了中文的类名称翻译.这样对cocos2d-x-3.0的框架比较好上手. 有兴趣的...

    Cocos2d-x高级开发教程制作自己的《捕鱼达人》

    Cocos2d-x高级开发教程:制作自己的《捕鱼达人》 图书简介: 《Cocos2d-x高级开发教程:制作自己的《捕鱼达人》》是国内第一本全面深入讲解Cocos2d-x进阶内容的图书,Cocos2d-x创始人王哲作序推荐,《捕鱼达人》开发...

    Cocos2D-X游戏开发技术精解.pdf

    《Cocos2D-X游戏开发技术精解》详细介绍如何使用Cocos2D-X引擎开发自己的移动平台游戏。全书共15章,主要内容包括:Cocos2D-X引擎简介;如何建立跨平台的开发环境;引擎的核心模块——渲染框架;如何实现动态画面和...

    cocos2d-x开发者文档(中文)2015-01-30

    因为最近在学cocos2d-x,找了半天在网上也找不到一个离线的文档,于是自己抽空做了一个,全部内容提取自cocos2d-x中文官网的文档页http://cn.cocos2d-x.org/article 目前只提取了cocos2d-x部分内容。因为内容比较多...

    精通COCOS2D-X游戏开发 基础卷_2016.4-P399-13961841.pdf

    精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发

    经典版本 方便下载 源码 旧版本 3.8 官网找不到了 cocos2d-x-3.8.zip

    经典版本 方便下载 源码 旧版本 3.8 官网找不到了 cocos2d-x-3.8.zip

    Cocos2d-x之Lua核心编程 配套代码

    Cocos2d-x之Lua核心编程 配套代码,没有对应的pdf的书,下载前请看清楚啊!

    Cocos2d-X案例开发大全

    资源名称:Cocos2d-X案例开发大全内容简介:《Cocos2d-X案例开发大全》包括大量基于Cocos2d-X开发的游戏案例,详细讲解了基于Cocos2d-X游戏引擎在Android及iOS平台下进行游戏开发的思路,能够快速帮助读者提升利用...

    Cocos2d-x 3.x游戏开发实战pdf含目录

    Cocos2d-x 3.x游戏开发实战pdf含目录,内容详细,强烈推荐给大家。

    Cocos2d-x-3.x游戏开发之旅

    Cocos2d-x-3.x游戏开发之旅-钟迪龙著 全新pdf版和附书代码(代码为工程文件,可复制) 附带目录标签

Global site tag (gtag.js) - Google Analytics