Предположим, у меня есть вот такая команда:
add video "user" "videoname"
Как мне так спарсить красиво, чтобы не париться со switch, вызвать нужную мне функцию. То есть как-то определять, что именно я хочу вызвать.
Чтобы "не париться со 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) {
}
}
Это можно реализовать с помощью рефлексии.
Вот простой пример:
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(...): название метода, типы параметров.
Продвижение своими сайтами как стратегия роста и независимости