好的猜测这个问题看起来很像:
What is the best way to replace or substitute if..else if..else trees in programs?
考虑这个问题已关闭!
我想重构看起来像这样的代码:
String input; // input from client socket.
if (input.equals(x)) {
doX();
} else if (input.equals(y)) {
doY();
} else {
unknown_command();
}
是检查来自套接字的输入以执行某些操作的代码,但我不喜欢if else
构造,因为每次向服务器(代码)添加新命令时都必须使用新的if添加哪个是丑陋的。删除命令时,还必须修改if else
。
答案 0 :(得分:8)
使用Map<String, Command>
方法Command
interface
execute()
收集这些命令。
Map<String, Command> commands = new HashMap<String, Command>();
// Fill it with concrete Command implementations with `x`, `y` and so on as keys.
// Then do:
Command command = commands.get(input);
if (command != null) {
command.execute();
} else {
// unknown command.
}
为了更进一步,您可以考虑通过扫描实现特定接口(在本例中为Command
)或类路径中的特定注释的类来动态填充地图。 Google Reflections可能对此有所帮助。
更新(来自评论)您还可以考虑将answer of Instantsoup与我的答案相结合。在buildExecutor()
方法期间,首先从Map
获取命令,如果Map
中不存在该命令,则尝试加载关联的类并将其放入{{1} }}。懒加载的排序。这比在我的回答中扫描整个类路径更有效,并且每次都像在Instantsoup的回答中那样创建它。
答案 1 :(得分:3)
一种方法是使接口ICommand
成为命令的一般合同,例如:
public interface ICommand {
/** @param context The command's execution context */
public void execute(final Object context);
public String getKeyword();
}
然后您可以使用Java的SPI机制自动发现您的各种实现,并在Map<String,ICommand>
中注册,然后执行knownCommandsMap.get(input).execute(ctx)
或类似的事情。
这实际上使您能够将服务与命令实现分离,从而有效地使这些服务可插入。
通过添加一个名为ICommand类的完全限定名称的文件来完成向SPI注册实现类(因此,如果它在包中,则文件将在类路径中为META-INF/dummy.ICommand
),并且然后你将加载并注册为:
final ServiceLoader<ICommand> spi = ServiceLoader.load(ICommand.class);
for(final ICommand commandImpl : spi)
knownCommandsMap.put(commandImpl.getKeyword(), commandImpl);
答案 2 :(得分:3)
界面,工厂和反思怎么样?您仍然需要处理错误输入的异常,但您总是需要这样做。使用此方法,您只需为新输入添加Executor的新实现。
public class ExecutorFactory
{
public static Executor buildExecutor(String input) throws Exception
{
Class<Executor> forName = (Class<Executor>) Class.forName(input);
return (Executor) executorClass.newInstance();
}
}
public interface Executor
{
public void execute();
}
public class InputA implements Executor
{
public void execute()
{
// do A stuff
}
}
public class InputB implements Executor
{
public void execute()
{
// do B stuff
}
}
您的代码示例将变为
String input;
ExecutorFactory.buildExecutor(input).execute();
答案 3 :(得分:2)
在枚举类上构建命令模式可以减少一些样板代码。我们假设input.equals(x)
中的x是“XX”而input.equals(y)
中的y是“YY”
enum Commands {
XX {
public void execute() { doX(); }
},
YY {
public void execute() { doY(); }
};
public abstract void execute();
}
String input = ...; // Get it from somewhere
try {
Commands.valueOf(input).execute();
}
catch(IllegalArgumentException e) {
unknown_command();
}
答案 4 :(得分:1)
你说你正在处理来自套接字的输入。多少输入?这有多复杂?结构如何?
根据这些问题的答案,您可能最好不要编写语法,并让解析器生成器(例如ANTLR)生成输入处理代码。