假设我正在编写一个聊天机器人(discord,电报等)。该机器人可以处理聊天命令(例如!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...
对我来说,这似乎是一种不好的做法,并且代码有异味。 有更好的方法吗?
答案 0 :(得分:2)
您可能希望依靠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
(实现)数据结构中。 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.
)
答案 1 :(得分: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);
答案 2 :(得分:0)
您好,您可以尝试使用Switch Case语句,这很容易理解,将来如果您有任何更改,也很容易更新代码。
switch(message)
{
case JOIN_MESSAGE:
return new JoinCommand();
break;
case LEAVE_MESSAGE:
return new LeaveCommand();
break;
}