Pull to refresh

Comments 7

UFO just landed and posted this here
Это API не подходящее под желаемый контекст применения.
В случае с Commons-cli потребовалось бы создание большого количества обвязок для получения того, что дает JCommander из-коробки.

Commons-CLI:
Options options = new Options();
options.addOption( "a", "all", false, "do not hide entries starting with ." );
options.addOption( "A", "almost-all", false, "do not list implied . and .." );
options.addOption( "b", "escape", false, "print octal escapes for nongraphic "
                     + "characters" );
options.addOption( OptionBuilder.withLongOpt( "block-size" )
                .withDescription( "use SIZE-byte blocks" )
                .hasArg()
                .withArgName("SIZE")
                .create() );
options.addOption( "B", "ignore-backups", false, "do not list implied entried "
                         + "ending with ~");
options.addOption( "c", false, "with -lt: sort by, and show, ctime (time of last "
                + "modification of file status information) with "
                + "-l:show ctime and sort by name otherwise: sort "
                + "by ctime" );
options.addOption( "C", false, "list entries by columns" );

String[] args = new String[]{ "--block-size=10" };

try {
  CommandLine line = parser.parse( options, args );

  if( line.hasOption( "block-size" ) ) {
    // print the value of block-size
    System.out.println( line.getOptionValue( "block-size" ) );
  }
}
catch( ParseException exp ) {
  System.out.println( "Unexpected exception:" + exp.getMessage() );
}


* This source code was highlighted with Source Code Highlighter.


JCommander+Guice:
@Parameters(commandDescription = "Command sample")
@Named("command-sample")
public class CommandSample extends Command {

  @Parameter(names = {"-a", "-all"}, description = "do not hide entries starting with ")
  protected boolean all;

  @Parameter(names = {"-A", "-almost-all"}, description = "do not list implied . and ..")
  protected boolean almostAll;

  @Parameter(names = {"-b", "-escape"}, description = "print octal escapes for nongraphic characters")
  protected boolean escape;

  @Parameter(names = {"-B", "-ignore-backups"}, description = "do not list implied entried ending with ~")
  protected boolean ignoreBackups;

  @Parameter(names = {"-c"}, description = "with -lt: sort by, and show, ctime (time of last \" \n" +
      "                + \"modification of file status information) with \"\n" +
      "                + \"-l:show ctime and sort by name otherwise: sort \"\n" +
      "                + \"by ctime")
  protected boolean c;

  @Parameter(names = {"-C"}, description = "list entries by columns")
  protected boolean C;

  @Parameter(names = {"--block-size"}, description = "block size")
  protected int blockSize;

  @Override
  public void execute() throws ExecutionException {
    if (blockSize > 0) {
      System.out.println(String.valueOf(blockSize));
    }
  }
}


* This source code was highlighted with Source Code Highlighter.


Второй вариант, на мой взгляд, выглядит более дружелюбно, поскольку работа ведется не в стиле процедурного программирования, а объектно — на выходе получаем инициализированный экземпляр Команды которая инкапсулирует свое состояние и поведение.

Конечно в этом примере не указан пример разбора строки через JCommander, основная идея в том, что паттерн Команда не поддерживается в Commons-CLI и такую поддержку нужно делать самостоятельно.

Второй подход одозначно приятнее.

Но я не вижу там особой поддержки паттерна «команда» — вы вручную написали класс CommandSample с методом execute(). Что мешает обернуть в это же самое первый пример? И будет та самая поддержка, разве нет?
Чтобы понять где-же там кроется паттерн нужно показать то, как конфигурирется JCommander (это происходит в JCommanderProvider):
commander.addCommand(command.getCommandName(), command, command.getAliases());


Метод addCommand это уже API JCommander-а — мы передаем ему имя команды, созданный экземпляр нашей команды и ее алиасы.

Класс команды должен расширять Object, главное — чтобы в классе поля-параметры были помечены аннотациями @Parameter и имели модификаторы доступа protected/public.
После этого мы выполняем разбор консольного ввода (CLISupport):

//args - ввод с консоли (массив строк полученны путем разбивки строки ввода по пробелам)
JCommander jCommander = injector.getInstance(JCommander.class);
jCommander.parse(args);
List

Почему автор фреймворка не ввел какой нибудь маркерный интерфейс, типа того же Executable или Command я сказать не могу - не знаю, но и с Object-ом все получается достаточно изящно. Самая неизящная часть всего действа находится как раз в CLISupport.

И конечно же, при желании, можно и Commons-CLI довести до подобного уровня.
Корректный код разбора ввода с консоли:

//args - ввод с консоли (массив строк полученны путем разбивки строки ввода по пробелам)
JCommander jCommander = injector.getInstance(JCommander.class);
jCommander.parse(args);
 List<Object> commands = jCommander.getCommands().get(parsedCommand).getObjects();
          for (final Object command : commands) {
            if (command instanceof Command) {
            // тут у нас полный инициализированный экземпляр Command - осталось только вызвать .execute()
            }
           }

* This source code was highlighted with Source Code Highlighter.

Sign up to leave a comment.

Articles