多年前,在我对C ++了解很多之前,我正在与一位经验丰富的程序员同事讨论创建事件系统等问题。 他似乎强调需要传递函数指针,以便可以通过回调来通知类状态变化等。
然而,现在每当我需要实现某种事件系统时,我只需构造一个伪接口类,继承它并使用subscriber / observer模式覆盖方法并分发事件。
前几天我在想,到目前为止,我很少需要使用函数指针,当然不是针对上述情况。我真正必须使用函数指针的唯一情况是与其他明确要求传递函数的.dll接口时。
我何时应该使用函数指针而不是订阅者/观察者模式?
使用其中一种是好/坏的做法? (可能必须存在观察者模式不比函数指针好的情况)。
请有人分享一些见解吗?在这方面获得更多经验会很好吗? (前面提到的同事已经转移到另一个企业,我们失去了联系)。我一直在讨论这个问题,并且无法想到何时使用观察者模式和界面不那么整洁。
谢谢!
我经常发现自己写作的课程示例(没有经过测试,完全不在我的脑海中,可能无法正常工作):
class NotifierListener {
friend class Notifier;
private:
vector<NotifierListener*> mListeners;
protected:
void subscribe(NotifierListener* _subscriber) {mListeners->push_back(_subscriber);}
virtual void onNotification();
}
class Notifier : public NotifierListener {
private:
void doSomethingAndNotify() {
...
if (mListeners.size() > 0) {
for (int i = 0; i < mListeners.size(); ++i) {
mListeners[i]->onNotification();
}
}
}
}
class Something : public NotifierListener {
Something() { subscribe(this); }
void onNotification() {
cout << "I got notified\n" << endl;
}
}
答案 0 :(得分:2)
正如wasthishelpful指出的那样,继承和函数指针是实现观察者模式的两种方式。
使用函数指针(或者特别是像C ++ 11的std::function
这样的东西)的主要优点是增加了灵活性。观察类不需要实现接口,并且可以任意命名被调用的成员函数。您甚至可以调用一个独立的函数或一个您不能或不想修改的对象的成员,以便它实现您的观察者界面。
另一方面,使用继承更简单,更直接。但除此之外,我想不出任何优于函数指针方法的优势。
答案 1 :(得分:2)
函数指针效率更高一些。您现在将指针传递给接口。接口通常*包含指向vtable的指针。而vtable又包含函数指针。这是间接的3个级别,参考位置较差。
[*]其他实现是可能的,但具有类似的开销。
答案 2 :(得分:1)
在Observer Pattern
中,侦听器是对接收事件采取某些操作的实体。大多数情况下,这些实体执行各自的工作并监听事件并根据接收事件时的状态来调用可能的不同操作。因此,更好的选择是具体对象应该是监听器,因为对象具有单独的状态。使用纯函数(将使用函数指针调用)以内聚/无缝方式维护这些状态有点困难。