简体   繁体   中英

How to share common class with non-common functions among components?

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 handle method:

class Component {
  virtual void executeFunctionABC() = 0;
  virtual void executeFunctionDEF() = 0;
}

class MessageA : public Message {
  void handle(Component *c) {
    c->executeFunctionABC();
  }
}

When the component receives a message, it would call:

message->handle(this);

Also, from your description, prepare and parse seem to be primarily used for creating / restoring a message, so I would make them factory methods (either a static method in Message or a separate MessageFactory class) instead of virtual methods on the Message class.


Edit: Alternatively, you can use the visitor pattern by having separate handle methods for each component:

class MessageA : public Message {
  void handle(ComponentA *c) {
    c->executeFunctionABC();
  }

  void handle(ComponentB *c) {
    ...
  }
}

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:

class MessageHandler {
  virtual void handle(MessageA *msg) = 0;
  virtual void handle(MessageB *msg) = 0;
}

class MessageA : public Message {
  void handle(MessageHandler *handler) {
    handler->handle(this);
  }
}

class ComponentA : public MessageHandler {
  void handle(MessageA *msg) {
    executeFunctionABC();
  }
}

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.

Could you separate Message as such from actions on message such as handling, parsing and preparing?

Try thinking in terms of MessageHandler, MessageParser and MessagePreparer. What parts of common Message interface they could use to access message's data? What will be different?

If this works out, component A will need MessageA_Preparer and MessageB_Handler and _Parser. Component B will need MessageB_Preparer and MessageB_Handler and _Parser.

This is not an answer to your existing problem of handling handle() function, but just want to ask you (as I also have interest in this sort of mechanism) why you let the message perform prepare(), parse() and handle()? I feel like there should be a sender class which should handle prepare() and a receiver class, which should handle parse(), and depending on the way you implement handle(), maybe that too.

Wouldn't it be better if Message class just include the message, and sender and receiver classes handle the other functionality?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM