This is a crosspost from my dev blog KR Game Studios. I've edited it for grammar and clarity.
This is a rare situration that not many programmers will come across, but since I did, I figured I'd write up a solution for those who do.
I had an enumeration with roughly 40 unique values, representing the type of message sent across a game network. To determine how to process the different types, I was using a massive switch statement like this:
switch(packet->type) { case PacketType::CHARACTER_CREATE: case PacketType::CHARACTER_DELETE: case PacketType::CHARACTER_LOAD: case PacketType::CHARACTER_UNLOAD: ... serializeCharacter(packet); break; case SerialPacketType::MONSTER_CREATE: ... }
You get the idea.
The problem was that every time I added to the enumeration, I had to update the switch statements to match; that's plural, by the way, becuase I had a second nearly identical switch statement for deserializing the messages on the other end.
I had been working with this pattern for roughly a year and a half; iterating on the code as I went along, until I was struck with a realization: I could simply add boundry indicators to the enumeration to highlight groups of packet types.
Once I had these, I could add new packet types to the enumeration without modifying any massive switch statements; I only had to modify the pseudo-switch statements when I add a new group of packet types.
Enough talk, here's the example:
//DOCS: FORMAT_* is for internal use enum PacketType { //login/logout protocol FORMAT_LOGIN, LOGIN_REQUEST, LOGIN_RESPONSE, LOGIN_REJECTION, LOGOUT_REQUEST, LOGOUT_RESPONSE, FORMAT_END_LOGIN, //character protocol FORMAT_CHARACTER, CHARACTER_CREATE, CHARACTER_DELETE, CHARACTER_LOAD, CHARACTER_UNLOAD, ... FORMAT_END_CHARACTER, //monster protocol FORMAT_MONSTER, MONSTER_CREATE, MONSTER_DELETE, ... FORMAT_END_MONSTER, ... }; int serialize(Packet packet) { //login/logout protocol if (packet->type > PacketType::FORMAT_LOGIN && packet->type < PacketType::FORMAT_END_LOGIN) { return serializeLogin(packet); } //chacacter protocol if (packet->type > PacketType::FORMAT_CHARACTER && packet->type < PacketType::FORMAT_END_CHARACTER) { return serializeCharacter(packet); } //monster protocol if (packet->type > PacketType::FORMAT_MONSTER && packet->type < PacketType::FORMAT_END_MONSTER) { return serializeMonster(packet); } //there's an error somewhere return -1; }
When not wrestling with the markdown editor, I'm programming an MMORPG from scrach called Tortuga, which can be found at krgamestudios.com. You can follow the major updates here: @KRGameStudios.
P.S. If you want to see the actual code (which might be clearer), here they are: