Создание объекта на основе строки - PullRequest
0 голосов
/ 10 марта 2019

Допустим, я пишу бота для чата (раздор, телеграмма, что угодно).Бот может обрабатывать команды чата (например,! Join говорит ему присоединиться к голосовому каналу на сервере).

Так что где-то в моем коде мне нужно будет проанализировать команду, и у меня будет что-то вроде

String userMessage = getTheMessageTextSomehow();
// Do something with the  message.

Я хотел бы иметь класс Command для каждой из моих команд, и каждая команда будет реализовывать метод execute ().

Мой вопрос: как лучше всегосоздать эти объекты команд?

Самый простой способ - создать большой объект CommandFactory или любой другой класс, который будет выглядеть как

if(message.equals(JOIN_MESSAGE) {
    return new JoinCommand();
} 
if(message.equals(LEAVE_MESSAGE){
    return new LeaveCommand();
}
//etc...

Это выглядит как плохая практика и запах кода для меня,Есть ли лучший способ сделать это?

Ответы [ 3 ]

2 голосов
/ 10 марта 2019

Возможно, вы захотите положиться на Map из Command с.
Я поясню, что для этого сценария использования Function или Supplier или любого другого стандартного функционалаинтерфейс совсем не идиоматичен.Избегайте этого.

Мы можем начать с создания Command интерфейса

interface Command {
   Result execute(); 
}

Или, если вам нужно принять аргумент

interface Command {
   Result execute(final Input input); 
}

, который будет иметь требуемыйреализации

class JoinCommand implements Command { ... }
class LeaveCommand implements Command { ... }
class NoopCommand implements Command { ... }

и т. д.
Теперь вам нужно будет сохранить эти определения в структуре данных key (команда) - value (реализация).A Map идеально подходит для этого.

Поскольку определение вашей команды будет String, тогда

static final Map<String, Command> COMMANDS = new HashMap<>(8);

static {
   COMMANDS.put("join", new JoinCommand());
   COMMANDS.put("leave", new LeaveCommand());
   // And so on
}

Использование довольно простое

final String userMessage = getTheMessageTextSomehow();
final String commandStr = extractCommand(userMessage);
final Command command = COMMANDS.getOrDefault(commandStr, NOOP_COMMAND);
command.execute();

Или, если вам придется принять аргумент

command.execute(yourInput);

Вы также заметите, что я использовал NOOP_COMMAND, это просто реализация без опций для Command , чтобы избежать работы с null.Это может быть, а может и не подходить.


Если вы используете Java 9+, Map также можно создать с помощью

Map.of(
   "join", new JoinCommand(), 
   "leave", new LeaveCommand(),
   // And so on.
)
0 голосов
/ 10 марта 2019

Здравствуйте. Вы пытаетесь использовать оператор Switch Case, это легко понять, и в будущем, если у вас появятся какие-либо изменения, вы легко сможете обновить код.

switch(message)
    {
       case JOIN_MESSAGE:
            return new JoinCommand();
            break;

       case LEAVE_MESSAGE:
            return new LeaveCommand();
            break;
    }
0 голосов
/ 10 марта 2019

Обычно это осуществляется с помощью картографирования. Было бы намного понятнее и понятнее реализовать это с помощью простого Map.

Например:

Map<String, Command> strategies = new HashMap<String, Command>(){{
  put(JOIN_MESSAGE, new JoinCommand());
  put(LEAVE_MESSAGE, new LeaveCommand());
}};

И его использование:

Command command = strategies.get(messageType);

Более того, вы можете определять стратегии создания (фабрики) начиная с Java 8, если вам нужно создавать команды в зависимости от некоторых параметров.

Map<String, Function<String, Command>> strategies = new HashMap<String, Command>(){{
  put(JOIN_MESSAGE,  param -> new JoinCommand(param));   // or JoinCommand::new
  put(LEAVE_MESSAGE, param -> new LeaveCommand(param));  // or LeaveCommand::new
}};

И его использование:

Command command = strategies.get(messageType);
command.process(param);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...