2

I want to implement a protocol layer which sits on top of the TCP/IP stack. There is a limited set of PDUs that can be sent and for each PDU there is a class which represents it in a structured form. Each class has a function to serialize the structured data into a ready-to-transmit form, and deserialize them into a structured form.

These PDUs are structurally very different, for example:

struct a_associate_ac : property 
{
      a_associate_ac() = default;
      void from_pdu(std::vector<unsigned char> pdu) override;
      std::vector<unsigned char> make_pdu() const override;
      pdu::TYPE type() const override;


      std::string called_ae;
      std::string calling_ae;
      std::string application_context;

      struct presentation_context
      {
            enum class RESULT
            {
               ACCEPTANCE = 0x00, USER_REJEC = 0x01,
               PROV_REJEC_NO_REASON = 0x02,
               ABSTR_CONT_NOT_SUPP = 0x03,
               TRANFS_SYNT_NOT_SUPP = 0x04
            };

            presentation_context() = default;
            unsigned char id;
            RESULT result_;
            std::string transfer_syntax;
      };

      std::vector<presentation_context> pres_contexts;
      std::size_t max_message_length;
};

compared to:

struct a_associate_rj: property
{
      a_associate_rj() = default;
      void from_pdu(std::vector<unsigned char> pdu) override;
      std::vector<unsigned char> make_pdu() const override ;
      pdu::TYPE type() const override;

      enum class SOURCE : unsigned char
      {
         UL_SERVICE_USER = 0x01, UL_SERVICE_PROV_ACSE = 0x02,
         UL_SERVICE_PROV_PRESREL = 0x03
      };
      enum class REASON : unsigned char
      {
         NOT_SPECIFIED = 0x01, APPL_CONT_NOT_SUPP = 0x02, CALLING_AE_NOT_RECOG = 0x03,
         CALLED_AE_NOT_RECOG = 0x07
      };

      REASON reason_;
      SOURCE source_;
};

All these classes inherit from an abstract superclass property. property is used by the layer class, which implements the protocol, in two member functions:

void send(const property* p);
std::unique_ptr<const property> receive();

This means if the user of the layer class receives a property and wants to access its members, they must check what kind of property was received using property::type() and downcast it to that type, which I find is quite irritating.

What can be done to solve this problem?

  • The syntax highlighting is a little messed up, I couldn't manage to get it done correctly. It should still be readable though. – Marius Herzog Aug 30 '14 at 14:00
1

It depends a little bit of what you are doing with these properties, but one pattern that would get around the explicit casting would be double-dispatch or 'visitor'. It's a common pattern that is used in operating on trees but it think it might suit your need. In c++ the only disadvantage is that there is a point where you might need to refer to all your properties explicitly. This is what a stub for this might look like:

class Property {
    virtual void visit(Visitor *visitor) = 0;
}

class SpecificPropertyA {
     void visit(Visitor *visitor) {
        visitor->handle(this);
    }
}

class Visitor {

    void handle(Property *)  {
        // This is catch all and will deal with not implemented handle functions
    }

    void handle(SpecificPropertyA* property) {
        // Do the specific work here
    }

    void handle(SpecificPropertyB* property) {
        // Do the specfic work here
    }
} 

You can have as many different types of Visitors that you want, by deriving from the visitor interface. E.g. implementing a logger as opposed to a processor.

Please note that this is just one way of separating functionality from data, depending on the problem you are trying to solve it might just be easier to supply each of your property with a process() function that gets called and does the appropriate work without having to expose the type.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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