In my scenario, I have Component A and Component B which communicates through a Message class.
My message class looks like this
class Message {
virtual void prepare();
virtual void parse();
virtual void handle();
};
Any message is a subclass of the Message class, for example:
class MessageA: public Message {
void prepare() {
...
}
void parse() {
...
}
void handle() {
componentA->executeFunctionABC(); // componentA is a global pointer
}
};
Component A is compiled with MessageA
Component B is compiled with MessageA
So say when Component A wants to send a message to Component B, it will instantiate a MessageA object, prepare() it and send it out. When Component B receives the message through the socket, it will parse() it and handle() it.
My problem now lies in the handle() function. only the receiver of a message will call the handle() function. The implementation of the handle() function needs to execute certain routines which involves functions in the receiving Component.
I can now solve this by using PREPROCESSOR like this:
void handle() {
#ifdef COMPILE_FOR_COMPONENT_A
componentA->executeFunctionABC();
#endif
}
But it looks ugly. I wonder if there is any design pattern that can do this correctly?
If your components implement a common interface, you can pass the component into the
handlemethod:When the component receives a message, it would call:
Also, from your description,
prepareandparseseem to be primarily used for creating / restoring a message, so I would make them factory methods (either a static method inMessageor a separateMessageFactoryclass) instead of virtual methods on theMessageclass.Edit: Alternatively, you can use the visitor pattern by having separate
handlemethods for each component:This works well if you have a few components with very different functionality. The interface approach works well if you have components with similar functionality.
Edit 2: To completely decouple the components, you can use a hybrid of the previous two solutions:
You still end up with an interface for the components, but you only have as many methods as there are messages. This is effectively what your preprocessor directive achieves.