1

Let's say I have a program called theprogram (the marketing team was on strike when the product was to be named). I start that program by typing, perhaps not surprisingly, the program name as a command into a command prompt. After that, I get into a loop (from the users standpoint, an interactive command-line prompt), where one command will be read from the user, and depending on what command was given, the program will execute some instructions.

I have been doing something like the following (in C-like pseudocode):

main_loop{
 in=read_input();
 if(in=="command 1")
  do_something();
 else if(in=="command 2")
  do_something_else();
 ...
}

(In a real program, I would probably encapsulate more things into different procedures, this is just an example.)

This works well for a small amount of commands, but let's say you have 100, 1000 or even 10 000 of them (the manual would be huge!). It is clearly a bad idea to have 10 000 ifs and else ifs after each other, for instance, the program would be hard to read, hard to maintain, contain a lot of boilerplate code... Yeah, you don't want to do that, so what approach would you recommend me to use (I will probably never use 10 000 commands in a program, but the solution should, at least preferably, be able to scale to that kind of massive (?) problems. The solution doesn't have to allow for arguments to the commands)?

2
  • What language? It matters because some techniques work better in one language than another.
    – S.Lott
    Mar 16, 2011 at 19:48
  • @S.Lott: No specific language, a multi-language approach would be best. I will though accept answers with C, Java or Python only approaches, as long as they are good.
    – Anto
    Mar 16, 2011 at 19:50

5 Answers 5

1

Read this.

http://docs.python.org/library/cmd.html

It's a good design and might be adapted to other languages without much trouble.

1
  • Seems like a wonderful module, and you can easily write a wrapper around it of course in case you want to use it from another language. Thank you +1
    – Anto
    Mar 16, 2011 at 19:57
1

I would suggest that you have a factory(pattern) that creats command(patterns). The input to the factory would be the command name (and may be the rest of the commandline for additional options) and the output the commandobject to be executed.

A powerful implementatin of this combination would map the commandname to a filename of a plugin to be executed.

Git use this approch.

Example

  • "Git add" executes the plugin "git-add.exe"
  • "Git tfs" executes the plugin "git-tfs.exe"
0

Probably the best language agnostic way to do this is to separate the handling of each command into a separate file, or at least separate functions or methods. You then somehow have an entered command be passed to the specific function/method to do the specific job.

This way you can cleanly separate different jobs from each other. While at first it might seem like lots of code and boilerplate, you will think differently when you have a hundred different commands. Scalability is key to this.

This of course requires code to pass the input to the proper function/method. Sometimes this is already done for you like in python mentioned by @S.Lott.

0

You could build a data structure containing commands and function pointers to a method to handle those commands. The data structure would depend on your needs, but two ideas would be a hash table (very fast) or a tree whose identifiers at each level are characters that make up the command.

For instance

 <root>
a      b
pple   a     l
       nnana ue

Here I took a shortcut of including the whole command once ambiguity was eliminated.

Now that you have a data structure setup your runtime process is to simply lookup what command was entered and pass on any arguments. However in order to build the structure you will need to fill it, whether you use a globally accessible registration function that each modules init function must call or a giant (potentially automatically generated) function to do so.

0

There are two parts to a CLI implementation, the processing of input and the input's interpretation (or execution).

As far as interpretation, the Interpreter design pattern applies because it is one natural way "to structure [interpretation] of commands at a CLI" as opposed to a gigantic if/else or switch statement.

Alternatively, the Command design pattern is an option that can be used alone or paired with Interpreter (as well as with the Chain of Responsibility pattern).

Not to sound as a GOF junkie, but design patterns can, at times, provide elegant solutions to problems lacking 'obvious' solutions. As far as the reading and conversion of input itself (as opposed to interpretation of commands), the Factory pattern suggested below is an excellent idea. This response isn't theoretical as I have seen/worked on implementations of CLI based on the suggested patterns, and they were quite effective.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.