java - 如何过度设计 shell

标签 java shell oop design-patterns

昨天我偶然发现了this question ,它询问使用 command design pattern 创建一个 OO shell* .

这让我很好奇,因为我一直讨厌我的 shell(一连串的 ifs 和 elses)。我 answered这个问题有一个完整的例子。

这里有一段描述主要思想的摘录

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();
            }
        }
    }

不过,我并不完全满意。我更喜欢声明式解决方案,您可以在其中指定命令并将它们映射到 Command 的适当实例界面。

我的问题是,我不确定如何处理复杂的输入,例如

collect sample <sequence<double>>

collect sample 1.0 1.5 1.33 1.45

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

我可以将命令实例交给 Reader对象,但我觉得阅读自己的输入不是他们的责任。他们应该有一个 CommandParameter对象等

但我不确定如何设计它。我曾经实现了一个二进制协议(protocol)解析库,它使用户能够通过 xml 定义协议(protocol),这似乎是一个解决方案(但很复杂)。

另一个问题是,如果 CommandParameter 出现格式错误,我该如何告诉用户格式错误发生的时间和地点?无法创建?


长话短说

所以以一个明确的问题结束: 可以使用哪些设计模式来创建一个干净的 shell (以声明的方式),同时尊重所有常见的 干净的代码规则(关注点分离、单一职责原则等)。

*with 'shell' 我的意思是 (java) 程序的一部分,它从 System.in 中读取预定义的命令。并调用模型/ Controller 上的相应方法。

最佳答案

大体上,在设计 shell 时有两种思路:

  1. Unix 哲学:“文本是通用界面”。大多数受 Unix 启发的工具从 stdin 读取文本并将文本输出到 stdout 以相互交互。这种将文本作为通用界面的哲学之所以出现,是因为这些工具是由大量异类作者用异类语言编写的,他们可能从未见过面或听说过彼此。一个工具可以是荷兰人用 C 写的,另一个是澳大利亚的一个团队用 Python 写的,还有一个是 Perl 脚本,在不同的论坛上被无数人传过和修改过,等等,他们需要互操作彼此。 Unix shell 具有强大的工具,可以转换文本流以将一个程序的输出提供给另一个程序(sed、grep 等)。缺点是每个工具都必须实现自己的解析。

  2. 基于对象的 shell,最著名的是 PowerShell,还有更传统的编程语言(如 Python、Ruby、Lisp)的 REPL。在这种理念下,​​您将在 shell 中拥有对象,而 shell 工具交换这些对象而不是文本。基于对象的 shell 通常更易于使用,假设工具的作者将他们的工具设计为可以一起使用(如果所有工具都是由一个作者或一个统一的作者组编写的,通常就是这种情况)。缺点是几乎所有内容都必须用一种语言或一组共享公共(public)运行时的语言(例如 .NET)编写。

无论哪种情况,设计模式都很简单。在 Unix shell 哲学中,工具在文件系统中以声明方式声明为程序,而 shell 只会执行这些程序。另一方面,在基于对象的 shell 哲学中,您需要动态导入类文件,并且需要使用内省(introspection),以便 shell 可以弄清楚如何调用该工具。

关于java - 如何过度设计 shell ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29411966/

相关文章:

java - 返回两个字符串作为方法签名

apache-flex - 当我在 Flex 中扩展 MX 类时,如何在 MXML 中引用它?

Javascript oop 实例

JavaPreparedStatements isClosed 性能

java - Java 类中可以有或不能有内部接口(interface)有充分的理由吗?

java - 如何使用 Log4j 将自定义属性记录到 AppInsight?

linux - 删除除最后 5 个文件夹之外的所有文件夹的 Shell 脚本

linux - 如何将一个文件的尾部与另一个文件的头部结合起来?

linux - 如何使用 while 循环仅读取特定模式的文件名

java - 画线,圈任何东西(Java)