求教回调函数与委托类的区别?

最近在看《cocos2d-x实战》-关东升著(C++卷,第一版),其中讲解Cocos的设计模式。
书中提到了【委托设计模式】与【观察者设计模式】
其中【观察者设计模式】是参照了【委托设计模式】,都有委托类的设定(主题→具体主题,观察者→具体观察者),但是在【观察者设计模式】的示例中,并没有使用委托类(当然也就没有使用委托接口),取代的方式就是使用函数回调
callfuncO_selector(ALayer::callBack)

因此有如下问题:
1.委托设计模式就是将接口(方法名、返回类型、参数类型)都定义好,用户去继承该接口并实现即可。这样子对吗?
2.在定义函数指针的时候,也需要保证(返回类型、参数类型),这样子的话,为什么不使用函数指针的形式来代替委托设计模式中的(委托类)?

第二问的代码示例:


“委托”——这个词汇,在C#语言里是语言的特性。在C++里是模拟这个特性,cocos2dx 3.0的事件分发系统就是模拟了“委托”,经典的“观察者模式”描述的是行为关系,“委托”描述的是架构关系。

“委托”的目的就是为了使“被观察者”和“观察者”二者解耦。在cocos2dx 3.0里是利用了C++的特性,std::function和std::bind。

比如创建一个自定义事件listener,它有一个成员变量std::function,绑定场景内一个节点A的某个成员函数。就实现了listener和A的成员函数绑定。因此A的这个成员函数的参数必须和前面listener的成员变量std::function一致。

1、是的,引擎设计出一个接口,你只要按这个规则绑定就行了。创建一个listener,然后绑定某个对象的成员函数。

2、回调可以用函数指针设计,但是,你要注意一个前提,cocos2dx引擎是如何管理事件内存的,这里,回调的是对象A的成员函数,不是普通的函数,成员函数绑定已经“创建对象”了。当这个节点A移除的时候,与“A的成员函数”绑定的listener也会移除,正常管理了内存。但是如果用普通函数,当节点A移除的时候,listener没有与A绑定,这个listener怎么移除?cocos这样设计都是为了内存管理。

callfuncO_selector(ALayer::callBack)后面要接一个addEventListenerWithScenePriority(e,this)的。指向类成员函数必须有个对象。这个this就是你的“委托类”创建的对象。

1赞

非常感谢
以下是个人的一些想法。问题较多:blush:
1.对std::function和std::bind目前只是略知皮毛,但是大致上也是比较接近于函数指针,那么就是使用std::function和委托其实都是预先规定好具体格式?
2.我有如下一个问题,正如监听事件中,我们使用的是std::function去实现的,也算是使用它们预定好的参数格式吧?这个时候假设cocos2d-x设置了一个EventListenerKeyboardDelegator类,里面定义了onKeyPressed等方法,使用Delegator与使用std::function不同,但是都是做同一件事对吗?

2.用如下格式编写的时候可能更能说明我还有一个不明白的地方。再第二点中提到,我们回调的一般都是类的成员函数,而在C++中调用类的成员函数的时候是通过对象去调用的,也就是我们要确保对象的存在,那么不论是函数指针或者说是std::function,我只要传这个对象作为参数过去就可以了嘛?

对于这个我个人理解就是,调用MazeScene::onTouchBegan这个类成员方法,而类成员就是this(即当前场景)这样的方法是否比我一开始提问图片中直接使用函数指针方便,而且能够避免你提到的内存管理问题?

其实所有困惑就是不知道它的运行原理,你花点时间看看事件处理的源码架构,不要太深入理解细节,理解大概,就知道怎么回事了。

listener是观察者,我们给它设计个接口,把回调任务委托给别人来做,所以有绑定。

cocos设计了绑定的接口,onTouchBegan等,你按它的形式绑定函数就行。

这个函数可以是普通函数,但是listener必须绑定一个场景内对象,方便listener释放,也就是取消这个观察者。

设计原理上是同一回事。

好的,非常感谢