This is not so much of a technical question, but rather a c++ design question.
Frequently it seems that I have to design programs which have to manage some a protocol which has some sort of connection, parsing stage and abstract view. Typically I try and design my programs with separation of concerns at the forefront.
I keep ending out with "stacks" of objects, a system sits ontop of a parser, which in turns sits ontop of a connection (often there are more layers). These objects then use member function calls to call a layer below it (Tx), and uses callbacks (std::function
, usually) to capture information coming from the other directions (Rx).
This design seems really subpar, as it add complexity, and each layer has to have a progressively bigger constructor and so on. Also because the connection usually uses something like ASIO, the callbacks are generally on different threads so it's hard to reason about thread saftey.
Is there a design patterm, or idiom that represent this structure/functionality better?
A simple example
class basic_connection {
basic_connection(std::string address);
void send(std::string);
std::function<void(std::string)> on_receive;
};
I have a few classes like this, which hold that layer's state, and are glue together by their public member functions and callbacks.
The layer above this, receives command data processes for the network and calls basic_connection::send
. And takes the raw data from basic_connection
and converts into commands for the layer above it unprocessed.
Another issue that I forgot to mention is that you end up forwarding some of the interface though the stack, for example, a top layer still needs to know the connection status.
Without having a set of requirements it's hard to recommend anything. However, from the high level description in your question it seems that you might want to use the model-view-controller pattern, maybe in conjunction with others. Remember, design patterns are your friends and you're the one who decides if usage is appropriate and to what degree. Design pattern are very easy to abuse and it's happening all the time.
It sounds like what you are trying to do is what is normally refered to as "constructing a pipeline".
Here is one simple way to connect two layers:
class I
{
virtual void a() = 0;
virtual void b() = 0;
}
class X
{
I& m_i;
X(I& i) : m_i(i) {}
void onRecv(const char* data, size_t len)
{
for (size_t p = 0; p < len; p++)
switch (data[p])
{
case 'a': m_i.a(); break;
case 'b': m_i.b(); break;
}
}
}
class Y : public I
{
void a() { ... }
void b() { ... }
}
int main()
{
X x;
Y y(x);
while (...)
x.onRecv(data,len);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With