I have some code that deals with receiving messages, parsing them, and handling them. I'm interested in making the types immutable to make it easier to reason about them. Here's a stripped down example:
class ReceivedMessage {
public:
ReceivedMessage(const string& message)
: m_message(message)
{ }
const string& GetReceivedMessage() const { return m_message; }
chrono::steady_clock::time_point GetReceivedAt() const { return m_receivedAt; }
private:
const string m_message;
const chrono::steady_clock::time_point m_receivedAt = chrono::steady_clock::now();
}
class ParsedMessage {
public:
ParsedMessage(const ReceivedMessage& rm)
: m_json(ParseMessage(rm.GetReceivedMessage()))
{ }
const string& GetJson() const { return m_json; }
private:
const json_t m_json;
}
class HandledMessage {
public:
HandledMessage(const ParsedMessage& pm)
: m_result(HandleMessage(pm))
{ }
const string& GetResult() const { return m_result; }
private:
const string m_result;
}
... and so on. This works fine, but at the end of the "pipeline", a response needs to be sent. To form the response, attributes from the first type (e.g., m_receivedAt
) are needed.
I'm not sure of the best/right way to pass those early attributes through to the final type. Here are my ideas:
- Inheritance seems simple, but my peers say I should favor composition over inheritance.
- Each type could hold a copy of the preceding message type (i.e., ParsedMessage would hold a ReceivedMessage) and delegate calls for information from the earlier types to it, so ParsedMessage would have an additional method like
chrono::steady_clock::time_point GetReceivedAt() const { return m_parentMessage.GetReceivedAt(); }
. This feels verbose, and there's a lot of repetition if information needs to be passed from the first type to the last. - Each message type could provide access to each of its parent message types, so to get
m_receivedAt
from a HandledMessage, it might look likehandledMessage.GetReceivedMessage().GetReceivedAt();
. This puts the burden of knowing which message type contains a particular attribute on the caller, though. I'm not sure that's something they need to deal with.
Aucun commentaire:
Enregistrer un commentaire