在命令模式中处理用户输入的位置

时间:2014-12-27 03:24:23

标签: design-patterns command-pattern

我正在处理客户端类中的用户输入,但我觉得通过执行此命令对象的execute方法,我将增加重用的能力,因为只需要实例化命令对象以使用其功能而不是依靠客户的实施。

因此,命令对象可能如下所示:

public class CommandA implements Command {
    ReceiverA receiverA;

    public CommandA(RecieverA receiverA) {
        this.receiverA = receiverA;
    }

    @Override
    public void execute() {
        Scanner scanner = new Scanner(System.in);

        String x = scanner.nextLine();

        receiverA.methodA(x);

    }
}

我发现缺少示例,所以我想知道这是否是一个'好'的做法,因为在我看到的示例中,命令对象只是使用接收器的方法。

2 个答案:

答案 0 :(得分:1)

希望用户能够直接输入一个用于命令行解析的库,或者使用BNF语法的简单生成的解析器将删除在客户端中放置一堆用户输入识别逻辑。

命令模式的优势在于允许客户端延迟执行命令或一系列命令,并允许客户端将命令传递给其选择的调用者。

以一些暴露CLI的系统为例,进行一些数据操作。我们假设您要为某些用户操作建模:'全部保存'和' print-sample'。这些命令中的每一个都可能缺少用户需要提供的一些所需数据。他们可能还有其他一些默认选项。您将使用命令行解析来分离通过命令行提供的用户输入,然后将解析的片段包装或提取到SaveAllPrintSample命令实例中。胶合逻辑只能使用正确的命令类型。您的代码将遵循:

String[] userInput = ...
Parsed parsedInput = parser.parse(userInput)
Command command;
switch (parsedInput.getCommandName()) {
  case 'save-all':
    command = new SaveAll(parsedInput);
    break;
  ...
}

如果你使用正确的工具,你甚至可以放弃这个胶水代码;有关Java / Scala的信息,请参阅JCommander

在您分离了拆分用户输入的问题之后,您的命令类将被赋予解析输入,例如:

public class SaveAll implements Command {
  private String targetName;
  private char separator = ','

  private DataSet dataset;
  private Filesystem filesystem;

  public SaveAll(Parsed input) {
    targetName = input.getTargetName();
    if (input.getSeparator() != null) {
      separator = input.getSeparator();
    }
  }

  @Injected
  public void setDataSet(...) { ... }

  @Injected
  public void setFilesystem(...) { ... }

  public void execute() {
    try (Datafile file = filesystem.openForWrite(targetName)) {
      for (Row row : dataset.rows()) {
        file.writeRow(row, separator);
      } // rows loop
    } // auto-resource
  } // end execute()
}

最后,在此示例中,客户端(向用户公开CLI的工具)可能允许用户连接到各种系统。在下面,它将为每个系统提供一个调用程序。因此该命令将被移交给适当的调用者。 (并且调用者可能会对命令进行序列化或排队。)

答案 1 :(得分:0)

使用GoF中初始模式定义的UML:

UML diagram of the Command pattern

我认为处理输入的的答案是什么?相当于Invoker类(或调用它的类)。

它绝对不是ConcreteCommands,因为目的是最终能够撤消或重做命令。如果依赖于在execute()方法中解析输入,则重新执行(对execute()的连续调用)将不起作用。

命令对象需要最少量的信息才能完成工作。这意味着它必须知道Receiver对象(对于每个命令可能不同)以及可能的命令的一些参数。在ConcreteCommand内部,我不会处理任何输入(即使它已被解析)。