我的情况如下。
我有一个抽象的Command
类,它有一个exec
方法。我有一系列具体的命令类来扩展这个抽象类。
我在上下文类中有一个CommandFactory
,它根据我解析并发送到工厂的cmdline args创建并返回一个合适的命令。 (这里没问题,我能解析cmdline args就好了。)
然而,在命令工厂中,我有一个if-else的大型列表,如果不是这个
public Command getCmd(String cmdType){
if(cmdType == null){
return null;
}
if(cmdType.equalsIgnoreCase("CLEAN")){
return new CleanCmd();
} else if(cmdType.equalsIgnoreCase("KILL")){
return new KillCmd();
} else if(cmdType.equalsIgnoreCase("START")){
return new StartCmd();
}
return null;
}
注意:输入参数是一组标志和参数,对于此问题的范围而言过于复杂。您可以将equalsIgnoreCase视为更复杂的东西。
但是我认为这个if else构造有点难看。我想用更优雅的东西取代它。如果我错了,还要纠正我当前的范例也违反了开闭原则,因为每次我添加一个新命令我都会修改工厂吗?
答案 0 :(得分:1)
如果可能,我建议使用两个概念:
命令模式,如此answer中所述,并使用一些依赖注入框架,如spring或guice。
有了这两个想法,您的代码可能是这样的:
class CommandFactory {
// Using spring.
// This will inject all the classes implementing Command.
@Autowired
List<Command> commandList;
// Mapping the command name to the implementation
Map<String, Command> commandMap;
// Initializing the command map
@PostConstruct
public void buildMap() {
for (Command command : commandList) {
commandMap.put(command.getType(), command);
}
}
public Command getCmd(String cmdType) {
return commandMap.get(cmdType);
}
}
使用此配置,CommandFactory类遵循Open Close Principle。无需修改即可添加新命令,但仍可按需接受新命令。
答案 1 :(得分:0)
做最简单的事情是没有错的,直到它不能满足你的需要为止。
一种方法是你可以完成你已经完成的工作,但稍微更整洁一点,就是使用基于字符串的switch
语句:
switch(cmdType) {
case "KILL":
return new KillCommand();
case "CLEAN":
return new CleanCommand();
default:
throw new UnknownCommandException("Unknown command: " + cmdType);
}
我注意到您对null
的特殊处理。我建议你尽量避免在任何地方返回null。如果你在整个过程中这样做,那么很多时候你也不需要检查空值。
如果您的需求变得更加复杂,请考虑使用Map<String,Command>
:
private static Map<String,Command> commandMap = new HashMap<>();
map.put("CLEAN", new CleanCommand());
map.put("KILL", new KillCommand());
...等,然后:
public Command getCommand(String cmdString) {
return commandMap.get(cmdString.toUpperCase());
}
请注意,每次返回相同的实例 - 如果您可以确保命令类本身是不可变且线程安全的,这通常是一件好事。
如果您每次都需要一个新实例,则可以选择:
Map<Class<? extends Command>>
并使用map.get(s).newInstance()
Map<Supplier<? extends Command>>
并使用map.get(s).get()
Map<SpecificCommandFactory>
并使用SpecificCommandFactory
中的方法(如果您尚未定义,我会称之为CommandFactory
)使用此模式意味着您可以在需要时准备好其他许多技术:
答案 2 :(得分:-1)
我建议使用原型设计模式代替您正在使用的命令静态工厂(if-then ... ladder)。由于要实例化的可能命令本质上是有限的,因此原型是生成命令的最佳模式。原型模式将保留预先填充的命令库,当客户端部分要求新命令时,它将从存储库获取所需的命令原型并提供克隆作为具体命令。