Flexible design to replace switch statement

I am working on a network program and designing a Linux server using C ++. It is simple enough to develop a basic structure. I have a package definition with a header that has a fixed size.

typedef enum{ PACKET_LOGIN_REQ = 1, PACKET_LOGIN_RES, PACKET_STORE_REQ, PACKET_STORE_RES }PACKET_TYPES; typedef struct { PACKET_TYPES type; short bodySize, long long deviceId }HEADER; . . /*more definitions here*/ typedef struct{ HEADER head; union BODY{ LOGIN_REQ loginReq; LOGIN_RES loginRes; . . more types } } 

Whenever I added more package types, I would have to change the switch statement to add more cases to handle newly added packages.

I use the type of union, so I do not need to change the whole structure of the package. Instead, I can add newly added package types to the union structure.

However, when I try to parse the raw data in order to put it in a package using the switch , I have to add every switch every time.

I think this is not a very good design, and I was wondering how I can structure the structure more flexibly.

Is there a better way to handle this (best design template)? What about relevant tutorials or links?

+4
source share
4 answers

You should use classes, and instead of switch use a polymorphic call.

Something like this (pseudo-codish):

 class Packet{ public: Packet(); virtual ~Packet(); virtual HandleMe()=0; protected: // fields } PacketTypeOne: public Packet{ public: virtual HandleMe(); // implementation for type 1 } PacketType2: public Packet{ public: virtual HandleMe(); // implementation for type 2 } PacketTypeX: public Packet{ public: virtual HandleMe(); // implementation for type X } 

and where do you get the packages:

 ... Packet* newPacket = PacketFactory::CreateNewPacket(packetTypeX); // factory will create // the right instance. ... // now handle it: newPacket->HandleMe(); ... 

Done.

+7
source

Since your code is C style, not C ++ style code, I will give you the answer C.

Use function pointers. Sort of:

 typedef int (*ParseFunc)(const char *, len, struct MyStruct); typedef struct PacketParser_ { PACKETType type; ParseFunc parseFunc; } PacketParser; const PacketParser[] parser = { { PACKET_LOGIN_REQ, LoginReqParser } { PACKET_LOGIN_RES, LoginResParser } . . . } 

Then you iterate over all types of packages and call the corresponding function. Whenever you get a new type of package, you simply add another line to your PacketParser function.

If you use C ++, you are better off using polymorphism.

+3
source

In most cases, you should avoid union s. This is one such case :-)

The answer, as noted, is to use polymorphism. The canonical way of converting switch statements to polymorphism uses a visitor design pattern .

While regular polymorphism can help you using virtual methods, a problem arises. The virtual methods give you the dispatch of the correct method based on a single object ( Packet ). But you also depend on what you need to do. For example, if you have many switch , rather than one, then the Visitor template will be preferable.

+1
source

You may want to ...

Essentially, you will find a good superclass and for each typecode create a separate subclass.

You also want to buy a copy of Refactoring: Improving the Design of Existing Code., Fowler, Martin (1999) / Addison Wesley. .

0
source

All Articles