Как вызвать функцию по команде?

376
21 декабря 2016, 00:25

Предположим, у меня есть вот такая команда:

add video "user" "videoname"

Как мне так спарсить красиво, чтобы не париться со switch, вызвать нужную мне функцию. То есть как-то определять, что именно я хочу вызвать.

Answer 1

Велосипед

Чтобы "не париться со switch" оформите каждое возможное действие в отдельный класс (паттерн проектирования Command).

public interface Command {
    void execute(List<String> args)
}

Возможные команды сложите в Map<String, Command>:

Map<String, Command> commands = new HashMap<>();
commands.put("add_video", new AddVideoCommand());

Разбирайте строку по пробелам. Первый элемент - имя команды, остальные - аргументы. Находите команду по имени и вызывайте:

String[] cmdLine = line.split(" ");
if (cmdLine.length == 0) throw new IllegalStateException("Command line is empty");
String cmd = cmdLine[0];
List<String> cmdArgs = Arrays.asList(Arrays.copyOfRange(cmdLine, 1, cmdLine.length - 1));
if (commands.containsKey(cmd)) {
    commands.get(cmd).execute(cmdArgs);
}

Этого хватит для команд вида add_video user videoname. Если вы хотите вложенные команды (add video ..., add user ...), можно воспользоваться паттерном Composite. Композитная команда должна просто содержать таблицу вложенных команд, находить нужную и передавать управление дальше.

public class CommandGroup implements Command {
    private final Map<String , Command> subcommands;
    public CommandGroup(Map<String, Command> subcommands) {
        this.subcommands = subcommands;
    }
    @Override
    public void execute(List<String> args) {
        if (args.size() == 0) throw new IllegalArgumentException("Not enough arguments");
        String subcommand = args.get(0);
        List<String> newArgs = args.subList(1, args.size() - 1);
        if (subcommands.containsKey(subcommand)) {
            subcommands.get(subcommand).execute(newArgs);
        }
    }
}

Теперь при сборке основной мапы с командами объединяйте вложенные команды вместе при помощи этого класса:

Map<String, Command> addCommands = new HashMap<>();
addCommands.put("video", new AddVideoCommand());
addCommands.put("user", new AddUserCommand());
Map<String, Command> commands = new HashMap<>();
commands.put("add", new CommandGroup(addCommands));

Готовое решение

Постепенно ваш командный фреймворк будет усложняться, и возможно вы захотите давать командам имена при помощи аннотаций и объявлять аргументы как параметры метода, находить команды динамически в CLASSPATH, генерировать справку по командам, вызывать команды из команд. В таком случае вам подойдет готовый фреймворк, решающий эти и многие другие проблемы. Например, можно взять CRaSH и добавление новой команды будет выглядеть на Java так (на Groovy еще лаконичнее):

public class add extends BaseCommand {
    @Usage("Adds new video")
    @Command
    public void video(@Usage("user name") @Option(names={"u","user"}) String user,
                      @Usage("video filename") @Option(names={"v","video"}) String video) {
    }
}
Answer 2

Это можно реализовать с помощью рефлексии.

Вот простой пример:

public class Main {
    public int inc(int value) {
        return ++value;
    }
    public static void main(String[] args) {
        Main main = new Main();
        try {
            Method method = Main.class.getMethod("inc", int.class);
            int newValue = (int) method.invoke(main, 1);
            System.out.println(newValue);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

Здесь метод int inc(int value) вызывается по текстовому представлению его имени.

Аргументы метода getMethod(...): название метода, типы параметров.

READ ALSO
Галерея на Spring

Галерея на Spring

ПриветДелаю галерею которая отображает все фотографии в папке

299
Cannot bind argument at index 2 because the index is out of range. The statement has 0 parameters

Cannot bind argument at index 2 because the index is out of range. The statement has 0 parameters

Вот такой exception вылетает, когда нажимаю кнопку "Войти"Обработчик:

494
Что значит тестовое задание &ldquo;в 2 экрана&rdquo;? [требует правки]

Что значит тестовое задание “в 2 экрана”? [требует правки]

Отправил резюме, получил в ответ вопрос: "готовы ли вы выполнить небольшое тестовое задание в 2 экрана?"

303
Приложение крашится из-за background service

Приложение крашится из-за background service

Доброго времени суток, суть проблемы:

350