0

We have a C++ project managed by UML software, which generates code for instantiating and passing data between objects. Unfortunately, this software adds a lot of overhead to our builds and development so we're looking to migrate our code away from it and cut out the generation step.

The generated code has container classes construct the objects, and then duplicates the interfaces so the internal methods are exposed externally:

class iMessageTx {
  public:
    virtual void sendMessage(const std::string& message) = 0;
};

class networkTx : public iMessageTx {
  public:
    void sendMessage(const std::string& message) { /* send message */ }
};

class networkStack : public iMessageTx {
  private:
    networkTx itsNetworkTx;
  public:
    networkStack() { itsNetworkTx = new networkTx(); }
    void sendMessage(const std::string& message) { itsNetworkTx.sendMessage(message); }
};

class hardwareLayer : public iMessageTx {
  private:
    networkStack itsNetworkStack;
  public:
    hardwareLayer() { itsNetworkStack = new networkStack(); }
    void sendMessage(const std::string& message) { itsNetworkStack.sendMessage(message); }
};

This is a lot to maintain by hand, not to mention debug through. It feels wrong to me, like this isn't a good design pattern.

Are there common patterns in C++ that are used to instantiate objects and orchestrate the communication between them? We'd move our code out of the UML software a little bit at a time, so we don't have to base our rewrite off its generated output.

  • It might help to know a little bit more about what happens with the various classes presented here. For example, are networkStack or networkTx exposed to any other code or used anywhere else? What does the code generation tool give you with this nested doll approach? – user1118321 Sep 28 '18 at 2:46
  • The object model diagram has links going from app code->hardware container->network stack container->network tx class, which is easy to follow visually. If this were written by hand however, I'm not sure what pattern should be used for our app to call sendMessage without tight coupling and with easy readability – codehearts Sep 28 '18 at 19:12
  • Is this the actual generated code? I’m confused because the snippet you posted does not even compile. The constructors try to assign a pointer to a non-pointer member variable, which is not possible. Also the code has other disastrous problems. Basically it’s completely broken. – besc Sep 29 '18 at 9:00
  • It's not the actual code, I wrote it by hand to illustrate the inheritance structure this thing builds. The real issue is every class has a sendMessage method when only one class is actually implementing it, and this is only done because in the UML we have links going from caller down to implementor – codehearts Sep 30 '18 at 21:34
  • "creating objects and orchestrating the communication between them" just sounds like a long way to say "programming" to me. You still need to know your problem and solution domains, and have a design, before you can worry about whether any bits of your design are described by an existing pattern. – Useless Nov 28 '18 at 12:06
0

Your question is confused. UML is notation for describing software, not managing it and whilst it can be used to generate code it isnt adding overhead in the way you describe. That said, Im not sure I see the problem, at least as you describe (caveat, I dont program C++).

I believe you have an interface iMessageTx that defines a behaviour sendMessage. You have 3 classes that implement this behaviour. The part I would do differently is that I would pass instances of iMessageTx to the using classes rather than have them instantiate their own members.

For example, either pass an instance of networkTx to networkStack in it's constructor , or using a setter. If networkStack only cares about the iMessageTx behaviour it should declare that it needs to be passed something that implements that behaviour, rather than that particular implementation, thus leveraging polymorphism. Similarly, for hardwareLayer.

This kind of wiring behaviour is what inversion of control frameworks are for. I wonder, though, if your design is quite right, as it implies that networkStack, networkTx and hardwareLayer are, for certain uses, interchangeable.

  • Our software draws UML diagrams and has a GUI editor for adding implementations based on those. I agree that the design isn't "quite right," but I'm not completely sure what is right. hardware->network->tx makes sense on a filesystem, but not for object inheritence. My biggest question is who should own tx, and how should tx be made available for app classes which need it? – codehearts Sep 30 '18 at 21:31
  • @codehearts That's difficult to say without understanding the domain. However, to take advantage of polymorphism, you should program to the interface, not the implementation. For example, hardwareLayer would be wired with something that implements iMessageTx, either through the constructor or a setter, rather than networkStack specifically. – Romski Oct 3 '18 at 4:02

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.