Unique class for each command in a command based protocol parser?
I'm writing a MSN Messenger client in C# and have opted to write my own parser for the MSNP protocol because I've looked at the source of other clients and I don't find the code to be up to my usual standard -- in particular a great lack of thought has been given to thread synchronization.
At first, I had written a generic parser that accepts "rules" which tell it how to parse commands.
For example, I set up a rule which dictates t开发者_运维技巧hat the command code "VER" has a transaction id, and a list of arguments.
This worked ok, but it had always been an interim solution. My intention had been to make a fully fledged parser which looked at each command and argument individually.
For example
if command code is "VER" then create a VersionCommand class, passing it the transaction id along with the list of accepted protocols.
then my code can easily interpret the command without messing with parameter indexes and such (verCmd.TrId & verCmd.AcceptedProtocols)
My concern is that it's wasteful of resources to use a separate class for each command type.
So my question is - is it wasteful? are there any other command based protocol implementations which take a similar approach? is there any precedent for what i want to do, or is it a moronic idea?
What you propose is not wasteful; rather, you're merely suffering the trade-off between "feature rich" and "simple" (regarding the interface and the parsing).
We've done what you propose a lot. The pivotal question: Can I make this simple (e.g., like a flat parsing "jump table"), or are my parsing demands and implementation requiring an infrastructure to permit future application-specific extension?
Based on the answer to the question, we've done both, a lot:
If "no", you have a discrete (long) list of (flat) parsing where you "attempt" to parse a command (with its parameters), fail, and then drop through to the next attempt, etc., until you've dropped through all twenty (or some number) of the commands that are "tested". Benefit: Flat, simple, each command can have its own custom parameters (because each parse attempt can validate the parameters specific to that command). This does not require you to have a class for every command (but you can if you want). For example, you could have a single MyCommand
class, which attempts to parse itself in twenty different ways to imply twenty different enumerated command types with different parameters.
If "yes", you are investing in a framework. Typically, this is to get an "engine" that can be extended in an application-specific manner. In our case, it also tends to reflect several hierarchies of commands, where each hierarchy can be "extended" for commands in application-specific ways. And, because these are separate hierarchies, we get great benefits in re-used state and logic (with common base classes for the different hierarchies). In this case, the "base" of each hierarchy "sniffs" the command, and if it matches, figures out which of the derived-most instances should perform the parsing-and-instantiation. This dramatically simplifies parsing, because you have different data handling needs for different hierarchies (and that code is established in the base), and you don't have one-monster-parser. Typically, we have a derived class for each command type, with its own custom parameter requirements. These derived classes are grouped in "hierarchies", which may (or may not) share a common base class (e.g., "tree" or "forest" model).
If you expect your protocol to be relatively bounded/unchanged, with consistent command parameters and types, "flat" works great. If you want application-specific extensibility, go ahead and invest in the one-command-per-class-type infrastructure -- after the "footwork" for initial implementation, it works GREAT, especially when you later realize your parameters are incorrect and you need to change implementation (which happens all the time). This is much easier to do with one-command-per-class (which also contains your command-specific parsing, rather than a super-monster-master-parser), although I concede it was a lot more code to get that infrastructure in place.
精彩评论