让我说我的switch/case
块真的很长,这让我内心说'看起来不好'
switch (option) {
case ERROR:
doSomething();
break;
case SUCCESS:
doSomething();
break;
case WARNING:
doSomething();
break;
case SUCCESS_WITH_WARNING:
doSomething();
break;
case SUCCESS_WITH_ERROR:
doSomething();
break;
case FATAL:
doSomething();
break;
case INFO:
doSomething();
break;
default:
break;
}
请记住,我们总是可以添加更多枚举等。
假设case
块中的方法正在向控制台打印内容。所以它们只是void
。
我试图使用访客,但是似乎有更好的选择,因此有了访客,它看起来像这样:
public enum ImportOption {
SUCCEEDED{
@Override
public void accept(ImportOptionVisitor visitor) {
visitor.visitSucceededImport();
}
},
FAILED{
@Override
public void accept(ImportOptionVisitor visitor) {
visitor.visitFailedImport();
}
},
WARNING{
@Override
public void accept(ImportOptionVisitor visitor) {
visitor.visitWarningImport();
}
};
public abstract void accept(ImportOption.ImportOptionVisitor visitor);
public interface ImportOptionVisitor{
void visitSucceededImport();
void visitFailedImport();
void visitWarningImport();
}
与之相比,我们得到了:
option.accept(new ImportOptionVisitor() {
@Override
public void visitSucceededImport() {
// TODO Auto-generated method stub
}
@Override
public void visitFailedImport() {
// TODO Auto-generated method stub
}
@Override
public void visitWarningImport() {
// TODO Auto-generated method stub
}
但是,即使对于100个枚举之类的长开关,它似乎也被夸大了。我读了一些有关命令模式的知识。但是我不确定如何实现它。有什么想法可以替换switch
并使代码更具可读性吗?
好,更多信息。该代码在Utils
类中实现,需要此开关块的方法如下所示:
public static void monitorDirectory(String zipDir, ImportOption option) {
String dirPath = FILE_PATH_TO_QUEUES_DIR + File.separator + zipDir;
try {
WatchService watchService = FileSystems.getDefault().newWatchService();
Path path = Paths.get(dirPath);
path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
WatchKey key;
while ((key = watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
String fileName = event.context().toString();
if (fileName.substring(fileName.lastIndexOf('.'), fileName.length()).equals(".7z")) {
//switch block here
break;
}
}
key.reset();
}
}
catch (IOException | InterruptedException e) {
e.printStackTrace();
}
它正在监视目录,当出现.7z文件时,它将开始根据ImportOption
枚举对该文件进行处理。该方法用作:Utils.monitorDirectory
。因此,我永远不会创建包含此方法的对象的实例(所以这可能是这段代码的问题)
答案 0 :(得分:2)
有很多方法可以解决这个问题。我提出了两个在可读性等方面相似的选项。
根据您所提供的信息(并假设您的每个doSomething()
都在做不同的事情),我只需要维护一个包含每个选项启动方法的映射即可。我在这里假设选项位于enum
中,但是如果选项是整数或字符串,则适用相同的原理。
private static final EnumMap<ExitCode, Runnable> runOnOption = new EnumMap<> (ExitCode.class);
static {
runOnOption.put(ERROR, () -> LOG.error("an error occurred"));
runOnOption.put(SUCCESS, () -> LOG.info("success"));
runOnOption.put(FATAL, this::runOnFatal);
}
private static void runOnFatal() {
//more complex recovery code
}
然后您的主要方法变为:
Runnable r = runOnOption(option);
if (r == null) throw new AssertionError("Missing option: " + option);
r.run();
另一种方法是将行为直接放在enum
中:
public enum ExitCode {
ERROR(() -> LOG.error("an error occured")),
SUCCESS(() -> LOG.info("success")),
FATAL(() -> {
//more complex code here
};
private final Runnable r;
ExitCode(Runnable r) { this.r = r; }
public void log() { r.run(); }
}
您的主要代码变为:
option.log();