Java 如何过度设计外壳
昨天我遇到了一个问题,它询问如何使用创建一个OO外壳 这让我很好奇,因为我总是讨厌我的贝壳(一连串的如果和其他)。我用一个完全有效的例子来回答这个问题 这里有一个小摘录,描述了主要思想Java 如何过度设计外壳,java,shell,oop,design-patterns,Java,Shell,Oop,Design Patterns,昨天我遇到了一个问题,它询问如何使用创建一个OO外壳 这让我很好奇,因为我总是讨厌我的贝壳(一连串的如果和其他)。我用一个完全有效的例子来回答这个问题 这里有一个小摘录,描述了主要思想 private final Writer writer = new BufferedWriter(new OutputStreamWriter( System.out)); private boolean quit = false; private Map<Stri
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();
}
}
}
private final Writer Writer=new BufferedWriter(new OutputStreamWriter(
系统(out),;
private boolean quit=false;
私有映射命令=new HashMap();
{
commands.put(“create”,newcreatechat(this));
commands.put(“join”,newjoinchat(this));
commands.put(“exit”,新ExitCommand(this));
}
public void run()引发IOException{
try(扫描器s=新扫描器(System.in)){
作者:写(“>”);
writer.flush();
而(!quit&s.hasNextLine()){
字符串输入=s.nextLine().trim();
//get或default是java8,或者您可以检查null
Command Command=commands.getOrDefault(输入,新的未知命令(此,输入));
command.execute();
如果(!退出)
作者:写(“>”);
writer.flush();
}
}
}
不过,我并不完全满意。我更喜欢声明式解决方案,您可以指定命令并将它们映射到命令
接口的适当实例
我的问题是,我不知道如何处理复杂的输入,例如
采集样本
采集样本1.0 1.5 1.33 1.45
或班主任学生…
我可以将命令实例交给Reader
对象,但我觉得读取自己的输入不是他们的责任。它们应该有一个CommandParameter
对象等
但我不知道如何设计它。我曾经实现过一个二进制协议解析库,它使用户能够通过xml定义协议,这似乎是一个解决方案(但很复杂)
另一个问题是,如果无法创建CommandParameter
,我如何告诉用户何时以及在何处发生格式错误
TL;DR 最后,我要提出一个明确的问题: 我们可以利用什么样的设计模式来创建一个干净的shell(以声明的方式),同时尊重所有常见的设计模式 清洁代码规则(关注点分离、单一责任原则等)
*“shell”是指(java)程序的一部分,它从
系统中读取预定义的命令,并在模型/控制器上调用相应的方法。广义上说,设计shell时有两种思想:
Unix理念:“文本是通用接口”。大多数受Unix启发的工具从stdin读取文本,并将文本输出到stdout以相互交互。这种将文本作为通用接口的理念之所以产生,是因为这些工具是由大量异构作者用异构语言编写的,这些作者甚至可能从未见过或听说过彼此。一个工具可以由荷兰的某个人用C编写,另一个工具由澳大利亚的一个团队用Python编写,另一个工具是Perl脚本,它已经在不同的论坛上被无数人传递和修改,等等,它们需要彼此互操作。unixshell拥有强大的工具,可以转换文本流,将一个程序的输出提供给另一个程序(sed、grep等)。缺点是每个工具都必须实现自己的解析
基于对象的shell,最著名的是PowerShell,但它也是Python、Ruby、Lisp等更传统编程语言的REPL。在这种理念中,shell中有对象,shell工具交换这些对象而不是文本。基于对象的shell通常更易于使用,前提是这些工具的作者已经将他们的工具设计为可以一起使用(如果所有工具都是由一个作者或一个统一的作者组编写的,则通常是这种情况)。缺点是,几乎所有内容都必须用一种语言或一组共享公共运行时的语言编写(例如.NET)
但无论哪种情况,设计模式都很简单。在unixshell哲学中,这些工具在文件系统中声明为程序,shell只执行这些程序。另一方面,在基于对象的shell理念中,您需要动态导入类文件,并且需要使用内省,以便shell能够确定如何调用该工具。如果您投票关闭,请添加注释。这给了我修改/澄清问题的机会。提前谢谢<代码>缺点是每个工具都必须实现自己的解析。
我指的正是那个解析。你如何设计它?我想我们对“壳”这个词有点误解。但是谢谢你有趣的回答@迈克:对于unixshell,解析由工具来完成,shell只有一些工具可以帮助转换文本。文本是通用的。在每个工具中,它们如何解析输入文本取决于工具,一些工具通过在Antlr、EBNF或Lex/Yacc中定义语法来完成整个过程,另一些工具只是通过数据使用regex,许多工具只是从输入流中使用令牌。它是决定如何最好地解析自己的输入的单独工具,shell不(需要)定义我们对解析的关注,它只需要设置流重定向。@mike:shell解析的唯一部分是命令行参数(argv数组)。在大多数unixshell中,这只是在空白处拆分命令行参数,并使用引号或转义字符防止拆分。然后由工具决定如何处理字符串数组。命令行完成只是作为单词列表或纸条实现的