Re: Looking for a simple design
{ Please limit your text to fit within 80 columns, preferably around 70,
so that readers don't have to scroll horizontally to read each line.
This article has been reformatted manually by the moderator. -mod }
On Tuesday, July 3, 2012 3:52:00 PM UTC+2, persres wrote:
Hi,
I am reading a binary message from the network stack at handle it
based on the message type.
void DispatchBinaryMessage(commonHeader *msg)
{
switch (msg->type)
{
case 'A' :
A *msgA = reinterpret_cast<A *> msg;
Handler(msgA); // Would be a better style to
write it as Handler<A>(msgA);
break;
case 'B' :
B *msgA = reinterpret_cast<B *> msg;
Handler(msgB); // Would be a better style to
write it as Handler<B>(msgB);
break;
etc.
}
}
I guess what I have is ok but feel something better is out there. Is
there a standard design pattern to capture this scenario nicely. It
is such a common situation that occurs in binary decoders. Any
additional comments regarding template usage or over-usage most
welcome.
Thanks
Similar question has been asked several times, either here or in the
non-moderated C++. So far, I have not seen anything simple yet effective
to deal with the issue. My understanding is: both at the low-level and
conceptual level, the problem is that code must be ready for the type of
data coming from outside. If data changes, code must be changed, end of
the story. You could introduce levels of indirection (e.g. a mapping of
message type to "handler" function, I've done that), but that doesn't
really buy you much, except that it avoids long switch statements left
and right. sufficiently low-level
As far as the switch goes, I don't know of a specific design pattern,
but perhaps you could avoid the switch by using a map. E.g.
typedef void (*HandlerFunction)(const commonHeader&);
typedef std::map<char, HandlerFunction> Handlers;
Handlers handlers = CreateHandlers();
void handlerA(const commonHeader& h)
{ Handle(static_cast<msgA&>(h)); }
void handlerB(const commonHeader& h)
{ Handle(static_cast<msgB&>(h)); }
....
Handlers CreateHandlers()
{
Handlers result;
result['A'] = handlerA;
result['B'] = handlerB;
// ...
return result;
}
void DispatchBinaryMessage(const commonHeader& h)
{
Handlers::iterator handler = handlers.find(h.type);
if (handler == handlers.end())
throw UnknownMessageType(h.type);
handler.second(h);
}
This is nothing interesting. I used "const" there because I don't think
you want to change your message while processing. I used references for
parameters because it looks like coming in with a null message is a caller
error, and callee (you) is not handling it. Using a reference in lieu of
a pointer at least sends a signal to the caller to watch out for null.
The way it is, blame for a null failure is spread between the two (caller
and callee), with no code-prescribed way to discern who should do what.
HTH,
Goran.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]