设计模式以避免消息传递中的下转换
Design pattern to avoid downcasting in message passing
基类MessageHandler
具有派生类。他们想互相传递信息。消息可以是不同的类,但可以共享一个基类。每个MessageHandler
如何避免对接收到的消息进行下行广播?是否有可能在MessageHandler上执行一些具有模板参数化虚拟receiveMessage
函数效果的操作?
从本质上讲,我试图用不向下转换的代码来替换以下代码,希望它是编译时的东西:
// ...
virtual void MessageHandler::receiveMessage(Message &msg) = 0;
// ...
// to receive a message
void DerivedMessageHandler::receiveMessage(Message& msg)
{
switch (msg.MsgType()) // enum
{
case Message::MessageType::A:
MessageA& = dynamic_cast<MessageA&>(msg);
break;
case Message::MessageType::B:
MessageB& = dynamic_cast<MessageB&>(msg);
break;
default:
// don't process unknown messages
break;
}
}
// to send a message
list<MessageHandler> mhList;
// populate list
for (MessageHandler& mh : mhList)
{
mh.receiveMessage(msg);
}
我知道我做不到,但像这样的东西
template <typename M>
void MessageHandler::receiveMessage(M& msg) {}
每个DerivedMessageHandler
都专门针对M
吗?什么样的设计模式可以让每个处理程序在其支持的消息对象上工作?
这很容易做到。通常有两种选择:
Boost.Variant
与其传递派生类,不如简单地枚举消息可能的类型。这些类型不需要相互派生。将这些类型封装在增强中::变体:
typedef boost::variant<MessageData1, MessageData2, MessageData3, ...> MessageData;
请注意,这意味着可能的消息数据类型必须是可枚举的。Variant的访问方法可以很容易地处理这些类型的对象,而不需要确切地知道它存储的是哪种类型。
Boost.Any
只需使用boost::any
:传递任何内容
void MessageHandler::receiveMessage(const boost::any &msg)
{
const MessageType1 *pMsg = boost::any_cast<MessageType1>(&msg);
if(!pMsg)
//Cannot process
return;
//Process message.
}
CCD_ 7类似于类型安全的CCD_。它会记住放入其中的确切类型,任何将其强制转换为其他的东西的尝试都将失败。boost::any
可以存储任何东西,因此得名。
它还具有值语义,因此可以像其内容一样进行复制。
如果我正确理解您的问题,您只需要使用虚拟函数进行直接继承。类似于:
class BaseMessage
{
public:
virtual ~BaseMessage() {}
virtual void processMsg() = 0;
};
class MessageA : public BaseMessage
{
public:
MessageA() {}
virtual ~MessageA() {}
virtual void processMsg()
{
// ... do something for MessageA ...
}
};
class MessageB : public BaseMessage
{
public:
MessageB() {}
virtual ~MessageB() {}
virtual void processMsg()
{
// ... do something for MessageB ...
}
};
在处理消息的地方,只需对收到的消息调用processMsg()函数,即可按照每个类中的指定处理每个消息。
std::auto_ptr<BaseMessage> m(mailbox.getMessage()); // Returns whatever msg is sent to your handler
m->processMsg();
您可以使用访问者模式。
但是访问者应该知道每个子类型并为其定义一个操作,所以没有默认的操作,AFAIK-
class Visitor;
class BaseMsg {
//..
public:
virtual void acceptVisitor(Visitor * v) = 0;
};
class Msg1;
class Msg2;
class Visitor {
// You can put here pure virtuals for sure every visitor will implement them
public:
virtual void action (Msg1 * msg) = 0;
virtual void action (Msg2 * msg) = 0;
};
class Msg1: public BaseMsg {
//..
public:
void acceptVisitor(Visitor * v){v->action(this);}
};
class Msg2: public BaseMsg {
//..
public:
void acceptVisitor(Visitor * v){v->action(this);}
};
class Visitor1 : public Visitor {
// ...
public:
void action (Msg1 * msg) {/*...*/ cout << "I like the message!n";}
void action (Msg2 * msg) {/*...*/ cout << "I hate the message!n";}
// more messages and actions for them
};
class Visitor2 : public Visitor{
// ...
public:
void action (Msg1 * msg) {/*...*/ cout << "Just finen";}
void action (Msg2 * msg) {/*...*/ cout << "Sorry, I'm busyn";}
// more messages and actions for them
};
int main() {
BaseMsg * a = new Msg1;
BaseMsg * b = new Msg2;
Visitor * act = new Visitor1;
Visitor * lazy = new Visitor2;
// ............
// somewhere in a deep deep forest of your code
a->acceptVisitor(act);
b->acceptVisitor(act);
// somewhere else
a->acceptVisitor(lazy);
b->acceptVisitor(lazy);
delete act;
delete lazy;
delete a;
delete b;
return 0;
}
输出:
- 我喜欢这个消息
- 我讨厌这个消息
- 很好
- 对不起,我很忙
相关文章:
- Libmosquitto publish 不会将所有消息传递到 Azure IoT Hub
- 线程消息传递或更好:在"大师班"中访问其他班级的成员
- 如何在 boost::asio 中将打包的结构作为消息传递?(无序列化)
- "Guaranteed Delivery"消息传递 - 我应该使用 MQTT 还是 ZeroMQ?
- 核心消息传递中未处理的异常.dll在程序关闭期间
- Microsoft具有本机消息传递和非持久连接的边缘扩展不起作用
- Firebase C 云消息传递背景问题
- 从客户端到浏览器的CEF中的消息传递序列化
- 我们是否可以使用 FireBase 云消息传递来发送或接收消息,或者在 Windows 桌面/控制台或 Linux 控制
- 如何将WM_KEYDOWN消息传递到 IWebBrowser2 实例
- 如何在 GNU Radio 中实现消息传递
- msgpack:C++和Java之间的消息传递
- 增强ASIO和线程之间的消息传递
- 交流时Chrome本机消息传递错误
- 多线程C++消息传递
- 跨平台最佳 MVC 模型到控制器消息传递方法(C#、Objective-C++)
- 如何在Chrome原生消息传递扩展的本机应用程序中使用本机主机消息
- 转换和传递数组
- 设计模式以避免消息传递中的下转换
- 消息传递从c++方法转换成Objective-C方法