如何避免静态方法中的长开关/大小写块

问题描述 投票:1回答:1

让我说我有很长的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。所以我永远不会创建包含此方法的对象的实例(所以这可能是这个代码的问题)

java design-patterns
1个回答
2
投票

有很多方法可以解决这个问题。我提出了两个在可读性方面类似的选项。

Option 1

根据您提供的信息(并假设您的每个doSomething()s正在做一些不同的事情),我只想维护一个包含每个选项启动方法的地图。我假设选项在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();

Option 2

另一种方法是将行为直接放在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();
© www.soinside.com 2019 - 2024. All rights reserved.