提问人:arvidj 提问时间:4/5/2009 最后编辑:skaffmanarvidj 更新时间:5/15/2011 访问量:1502
编写一个更简洁、更模块化的命令解析器
Writing a cleaner and more modular command-parser
问:
我正在为 Z80 模拟器编写调试器,我们正在学校项目中使用 Java。调试器从用户那里读取命令,执行该命令,读取另一个命令,等等。
命令可以是少参数、具有可选参数或采用无限数量的参数。参数大多是整数,但有时它们是字符串。
目前,我们使用 Scanner 类来读取和分析输入。read-method 看起来有点像这样(我是在脑海中写下这个,不注意语法或正确性)。
这是在项目开始时编写的 kludge,随着我们向调试器添加越来越多的命令,它很快就失控了。
我对这段代码的主要问题是大量的重复,if/else嵌套的高水平,以及周围的丑陋。
我想就如何使这段代码更美观和模块化,以及什么样的模式适合这种程序提出建议。
我还想对代码风格提出更一般的建议。
答:
你有没有考虑过用地图进行调度?哈希图很容易放在那里。只需将键设为命令,并创建一个接口或抽象类,该接口或抽象类是这样的命令:
interface Commmand {
void execute(String args);
}
或者更好的是,你可以提前把论点切碎:
interface Commmand {
void execute(String[] args);
}
然后你会使用 HashMap<String,Command>。
是的,有一种更简单/更好的方法,尤其是在 Java 或其他 OO 语言中。
首先,基本的见解是,命令解析器是一个有限状态机:START 状态是一个空行(或行首的索引)。
让我们考虑一下:echo
$ echo foo bat "bletch quux"
将线条分成几部分:
“回声”“噗
在贝壳中,语法通常是动词名词......所以这样解释。你可以用一系列 if-else if 的东西来做到这一点,但哈希更好。使用字符串作为索引加载哈希,并为其他内容编制索引。它可能只是一个数字,它会进入一个开关:
(这是伪代码):
Hashtable cmds = new Hashtable();
enum cmdindx { ECHO=1, LS=2, ...}
cmds.add("echo", ECHO); // ...
// get the token into tok
switch (cmds.get(tok)) {
case ECHO: // process it
// get each successor token and copy it to stdout
break;
...
default:
// didn't recognize the token
// process errors
}
更好的是,您可以应用命令和对象工厂模式。现在你有一个类 Command
public interface Command {
public void doThis(String[] nouns) ;
public Command factory();
}
public class Echo implements Command {
public void doThis(String[] nouns){
// the code is foreach noun in nouns, echo it
}
public Command factory(){
// this clones the object and returns it
}
}
现在,您的代码变为
// Load the hash
Hashtable cmds = new Hashtable();
cmds.add("echo", new Echo()); // one for each command
// token is in tok
// the "nouns" or "arguments are in a String[] nouns
((cmds.get(tok)).factory()).doThis(nouns);
看看这是怎么回事?在哈希中查找对象。调用该方法以获取新副本。然后,使用该方法调用该命令的处理。factory
doThis
更新
这可能有点太笼统了,因为它使用了 Factory 模式。为什么要有工厂方法?主要是,你要用它来使每次执行命令时,“verb”对象(如 的实例)都可以有自己的内部状态。如果不需要状态来长时间保留,可以将其简化为Echo
(cmds.get(tok)).doThis(nouns);
现在,它只是获取并使用您在实例化它时创建的对象。Echo
cmds.add("echo", new Echo());
评论