jeudi 2 avril 2015

How to overdesign a shell

Yesterday I stumpled upon this question, it asks about creating a OO shell with use of the command design pattern.


It made me curious, because I always hated my shells (a cascade of ifs and elses). I answered the question with a fully working example.


Here's a little excerpt that depicts the main idea



private final Writer writer = new BufferedWriter(new OutputStreamWriter(
System.out));
private boolean quit = false;

private Map<String, Command> commands = new HashMap<>();
{
commands.put("create", new CreateChat(this));
commands.put("join", new JoinChat(this));
commands.put("exit", new ExitCommand(this));
}

public void run() throws IOException {
try (Scanner s = new Scanner(System.in)) {
writer.write("> ");
writer.flush();
while (!quit && s.hasNextLine()) {
String input = s.nextLine().trim();

// get or default is java8, alternatively you could check for null
Command command = commands.getOrDefault(input, new UnknownCommand(this, input));
command.execute();

if (!quit)
writer.write("> ");
writer.flush();
}
}
}


Still, I'm not completely pleased. I'd prefer a declarative solution, where you can specify the commands and map them to a appropiate instance of the Command interface.


My problem herin is, that I'm not sure how to handle complex inputs, e.g.


collect sample <sequence<double>>


collect sample 1.0 1.5 1.33 1.45


or class teacher <name> pupils <name> <name> ...


I could hand the command instances a Reader object, but I feel it is not their responsibility to read their own input. They should have a CommandParameter object etc.


But I'm not sure how to design it. I once implemented a binary protocol parsing library which enabled the user to define the protocl via xml, that seems like a solution (but a complex one).


Another question is, how do I tell the user when - and where exactly - formatting errors occur, in case the CommandParameter can't be created?




TL;DR


So to finish with a clear question: What are the design patterns one can utilize to create a clean shell (in a declarative way), while respecting all the common clean code rules (separation of concerns, single responsibility principle, etc.).


Aucun commentaire:

Enregistrer un commentaire