基于String的对象创建

问题描述 投票:0回答:3

假设我正在为聊天写一个机器人(不和,电报,等等)。机器人可以处理聊天命令(例如!join告诉它加入服务器上的语音通道)。

所以我的代码中的某个地方我必须解析命令,我会有类似的东西

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

我想为每个命令都有一个Command类,每个命令都会实现一个execute()方法。

我的问题是:创建这些命令对象的最佳做法是什么?

最简单的方法是拥有一个大型CommandFactory或任何类somwhere,就像这样

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

这看起来像是一种糟糕的做法和代码味道。有没有更好的方法呢?

java oop design-patterns chatbot
3个回答
2
投票

你可能想依靠MapCommands。 我将清楚地表明,对于这个用例,使用FunctionSupplier,或任何标准功能界面都不是惯用语。躲开它。

我们可以从构建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(实现)数据结构中。一个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
投票

通常,它是通过映射实现的。用简单的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);

0
投票

您好,您可以尝试使用Switch Case语句,它很容易理解,将来如果您有任何更改,则可以轻松更新代码。

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

       case LEAVE_MESSAGE:
            return new LeaveCommand();
            break;
    }
© www.soinside.com 2019 - 2024. All rights reserved.