C++中的通用观察者模式
Generic observer pattern in C++
在我的应用程序中的许多情况下,我需要类A将自己注册为类B上的侦听器,以便在发生某些事情时接收通知。在每种情况下,我都定义了一个单独的接口B实现,a可以调用do
void registerSomeEventListener(SomeEventListener l);
此外,在许多情况下,B需要支持多个侦听器,因此我重新实现了注册和notifyAll逻辑。
我知道的一种通用方法是拥有一些EventListener(由A实现)和EventNotificationer(由B实现)类。在这种情况下,每个事件都由一个字符串标识,a实现方法:
void eventNotified(string eventType);
我认为这不是一个好的解决方案。如果A侦听多个事件,它将导致许多if-else语句,并且当仅在侦听器或通知程序中更改事件名称时,可能会导致错误。
我想知道在C++中实现观察者模式的正确方法是什么?
看看boost::signals2。它提供了一种通用机制来定义其他对象可以注册的"信号"。然后,信号所有者可以通过"发射"信号来通知观察者。受试者将信号定义为成员,然后跟踪连接的观察者,并在启动时通知他们,而不是注册方法。信号是静态类型的,并接受具有匹配签名的每个函数。这样做的优点是不需要继承,因此与传统的观测器继承层次结构相比,耦合性较弱。
class Subject {
public:
void setData(int x) {
data_ = x;
dataChanged(x);
}
boost::signals2<void (int)> dataChanged;
private:
int data_;
};
class Observer {
public:
Observer(Subject& s) {
c_ = s.dataChanged.connect([&](int x) {this->processData(x);});
}
~Observer() {
c_.disconnect();
}
private:
void processData(int x) {
std::cout << "Updated: " << x << std::endl;
}
boost::signals2::connection c_;
};
int main() {
Subject s;
Observer o1(s);
Observer o2(s);
s.setData(42);
return 0;
}
在本例中,主题保存一些int数据,并在数据更改时通知所有注册的观察者。
假设您有一个通用的事件触发对象:
class base_invoke {
public:
virtual ~base_invoke () {};
virtual void Invoke() = 0;
}
但你想在不同类型的对象上触发事件,所以你从基础上派生:
template<class C>
class methodWrapper : public base_invoke {
public:
typedef void (C::*pfMethodWrapperArgs0)();
C * mInstance;
pfMethodWrapperArgs0 mMethod;
public:
methodWrapper(C * instance, pfMethodWrapperArgs0 meth)
: mInstance(instance)
{
mMethod = meth;
}
virtual void Invoke () {
(mInstance->*mMethod)();
}
}
现在,如果您为指向base_invoke的指针集合创建一个包装器,那么您可以调用每个激发对象,并在您想要的任何类上发出任何方法的信号。
您也可以将此集合类变成烧制对象的工厂。简化工作。
class Event {
protected:
Collection<base_invoke *> mObservers;
public:
// class method observers
template<class C>
void Add (C * classInstance, typename methodWrapper<C>::pfMethodWrapperArgs0 meth) {
methodWrapper<C> * mw = NEW(methodWrapper<C>)(classInstance, meth);
mObservers.Add(ObserverEntry(key, mw));
}
void Invoke () {
int count = mObservers.Count();
for (int i = 0; i < count; ++i) {
mObservers[i]->Invoke();
}
}
};
你已经完成了艰苦的工作。在您希望侦听器订阅的任何位置添加一个Event对象。您可能想要扩展它以允许删除侦听器,并且可能需要一些函数参数,但核心基本相同。
- 如何设计具有不同类型的通知和观察器的观察者模式?
- 反射 + 函数指针与观察者模式
- 观察者模式不起作用
- 观察者模式:为什么主题应该是抽象的?
- 观察者模式专业化
- 如何在不必绑定到特定类的情况下实现观察者模式
- C++,函数指针与观察者模式
- C++11观察者模式(信号、插槽、事件、更改广播器/侦听器,或任何您想称之为的东西)
- 实施观察者模式C
- C++自己的观察者模式
- 不同可观察量的观察者模式
- 通过Boost信号的观察者模式2
- 具有类型信息的观察者模式(C++)
- 代码设计:观察者模式
- 观察者模式和继承:未调用正确的函数
- C++和Qt:观察者模式错误
- 在C++中实现观察者模式
- 多少听众是太多的观察者模式
- 当观察者希望观察不同的项目时实现观察者模式
- 通用观察者模式