C++无法弄清楚CRTP观察器模式设计



我正在尝试一个允许自动观察者/观察功能的模板设计。我有两个嫌疑人:

  • 静态继承没有按照我在Observing::notify()上期望的方式发生。
  • 我尝试绑定到模板TYPE类中的enum classTYPE::Status模板化参数。
#include <iostream>
#include <set>
// Observer base class
template <class TYPE>
struct Observing
{
template <class STATUS = TYPE::Status>
void notify(STATUS status);
protected:
// Constructed only through inheritance
Observing()  { TYPE::subscribe(this); }
~Observing() { TYPE::unsubscribe(this); }
};
// Class being observed
template <class TYPE>
struct Observable
{
static void subscribe   (Observing<TYPE>* obs) { observers.insert(obs); }
static void unsubscribe (Observing<TYPE>* obs) { observers.erase(obs); }
static std::set<Observing<TYPE>*> observers;
};
// Static definition of observable object's observers container
template <class TYPE>
std::set<Observing<TYPE>*> Observable<TYPE>::observers;
// Implementation of an observable service
struct Service : Observable<Service>
{
enum class Status { Up, Down };
void broadcast(Status status)
{
for (Observing<Service>* obs : observers)
obs->notify(status); // <--- unable to link `notify()`
}
};
struct Process: Observing<Service>
{
void notify(Service::Status status)
{
switch (status)
{
case Service::Status::Up:   std::cout << "Service is UPn"; break;
case Service::Status::Down: std::cout << "Service is DOWNn"; break;
}
}
};
int main()
{
Service service;
Process worker;
service.broadcast(Service::Status::Up);
}

我想也许Process::notify()的定义为时已晚,但我试图将声明放在Service上面,将定义放在下面,但随后我不得不向前声明Service并且找不到声明Service::Status的方法。

也许我的方法太复杂了...

在我的理解中,你想要实现的东西是行不通的。在此代码中,编译器只能在结构Observing中找到一个没有主体的notify函数。所以链接器稍后会抱怨它。

for (Observing<Service>* obs : observers)
obs->notify(status); // <--- unable to link `notify()`

让我们尝试帮助编译器选择正确的函数。由于我们处于编译时,因此可以使用static_cast。让我们试试:

static_cast<To what?>(obj)->notify(status);

这个问题的答案(static_cast什么)只能在运行时获得 - 这导致我们进入动态多态性。

因此,您必须尝试另一种解决方案:要么使用运行时多态性,要么更改类的体系结构。

观察者模式的要点是主体不知道观察者的静态类型。您将需要virtual.这意味着notify不能成为模板,您需要修复Observable的哪个成员表示要notify的参数。

template <class TYPE>
struct Observing
{
using Status = typename TYPE::Status;
virtual void notify(Status status);
// ...
};

为了安全起见,请在覆盖它的位置添加override

struct Process: Observing<Service>
{
void notify(Status status) override;
};

最新更新