【问题标题】:How to avoid static_cast in Pub/Sub system? (C++)如何避免 Pub/Sub 系统中的 static_cast? (C++)
【发布时间】:2021-06-11 07:06:43
【问题描述】:

我正在设计一个简单的 Pub/Sub 系统(基于 Boost Signals2)。在此系统中,您可以通过EventManager::subscribe 订阅特定类型的事件。然而,令人沮丧的是,每个订阅者都必须将const Event& 投射到他们订阅的特定事件中。避免这个问题的好/优雅的方法是什么?我很高兴改用完全不同的设计。

#include <iostream>
#include <functional>
#include <string>

class Event {
  virtual std::string get_type() = 0;
};

class EventA : public Event {
  std::string get_type() override {
    return "EVENT_A";
  }
  int get_foo() {
    return 5;
  }
};

class EventManager {
 public:
  void publish_event(const Event &e);
  void subscribe(std::string type, std::function<void(const Event &)> subscriber);
};

int main() {
  EventManager event_manager;
  event_manager.subscribe("EVENT_A", [&](const Event &e) {
    const EventA &event_a = static_cast<const EventA &>(e); // how can avoid cast here?
    // do stuff with event_a
  });

  EventA event_a;
  event_manager.publish_event(event_a);
}

【问题讨论】:

  • 从您描述的有限信息来看,很难判断。如果您的“订阅者”功能仅使用 Event 提供的功能,则不需要静态转换,例如Event 提供函数 get_foo() 并且(如果是 virtualEventA 覆盖它。如果您希望EventA 具有Event 不知道的功能 - 并且让您的“订阅者”直接调用它们 - 那么您需要static_cast。根据您的需要,您可能需要查找将对象与算法分开的技术 - 例如访问者设计模式或“双重调度”技术。

标签: c++ c++11 events event-handling publish-subscribe


【解决方案1】:

是的,这是典型的瓶颈模式,您的多态性不能满足您的需求。它使您可以通过同一个孔挤压不同的数据,然后再弄清楚它是什么。所以你必须订阅某种字符串名称来“base”事件,比如:

void subscribe(std::string type, std::function<void(const Event &)> subscriber); 

您可能想要使用特定类型的处理程序订阅特定事件:

void subscribe(std::function<void(const SquareEvent &)> subscriber); 
void subscribe(std::function<void(const RoundEvent &)> subscriber); 

或者,也许您甚至希望为此进行通用订阅:

template<class E>
void subscribe(std::function<void(const E &)> subscriber) {
     // implement 
} 

后者必须在标题中实现。如果您这样做,则无需将EventA&amp; 转换为Event&amp;,然后在处理程序Event&amp; 中转换回EventA&amp;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-20
    • 2021-04-17
    • 1970-01-01
    • 2015-04-26
    • 1970-01-01
    • 2012-04-25
    • 2017-06-18
    • 2022-06-22
    相关资源
    最近更新 更多