java if else 重构

java Refactoring if else

我有这个 if else 代码,我想知道是否有更多 useful/intelligent 的编写方式:

public void saveContent() throws Exception {
   if(book.isColored()) {
      book.setChoosen(“1234”);
   } else if (book.isAvailable()) {
      book.setChosen(“23498”);
   } else if (book.isAdults()) {
      book.setChosen(“0562”);
   } else {
      ReaderResponse response = reader.getReaderResponse();
      if (response != null) {
         book.setChosen(response.getName());
         }
      } else {
            book.setChosen(“4587”);
      }
   }
}

方法returns无效。

Switch 语句无济于事,因为您正在检查不同种类的属性。我会使用 if statements 但我会使用一些 static final 常量而不是 "magical numbers"。我会将最后一个 else 语句的内部删除到一个单独的方法中。

这中间引入一个局部变量就出问题了。解决这个问题的一种方法是引入另一种方法 - 不要害怕小方法。

public void saveContent() throws Exception {
    book.setChoosen(
        book.isColored()   ? “1234"  :
        book.isAvailable() ? “23498” :
        book.isAdults()    ? “0562”  :
        readerResponse()
    );
}
private String readerResponse() throws Exception {
    ReaderResponse response = reader.getReaderResponse();
    return response == null ? “4587” : response.getName();
}

? :是条件运算符,常被称为三元运算符。

如果getReaderResponse没有副作用,您可以重复调用。 get 方法 通常 没有副作用,但我觉得这里可能会有副作用。我不确定 Exception 抛出的位置 - 我假设它打算用子类型替换。

您可以实施策略设计模式来替代 if-else 构造

好吧,这是我考虑了几个月的问题。在我看来,对于非高级程序员来说,以一种聪明且可重复的方式编写代码并不容易。一个好方法是使用 switch 语句,但这不适用于布尔语句。

我会使用问题中提到的代码,但我会将其移至单个 class/controller/service 以获得更复杂的代码(这对于测试复杂行为会更好)。

我不会说这是更有效、更有用或更聪明的方法,但我当然认为通过将实际选择的代码解析委托给不同的方法,代码将更清晰和可测试:

public void saveContent() throws Exception {
   String choosenCode = getChoosenCode(book);
   book.setChoosen(choosenCode);
}

static String getChoosenCode(Book book) throws Exception {
   if (book.isColored()) {
      return “1234”;
   }
   if (book.isAvailable()) {
      return “23498”;
   }
   if (book.isAdults()) {
      return “0562”;
   }
   ReaderResponse response = reader.getReaderResponse();
   return (response != null) 
      ? response.getName()
      : “4587”;
}

如您所见,由于早期的 return 方法,不需要无穷无尽的 if-else 块。这也提供了对所选代码部分进行单元测试的能力,如果您有 void returning 方法,这会稍微复杂一些。

只是想添加一个 Stream 版本,但我认为它不足以满足少数情况。

List<Pair<Predicate<Book>, String>> mapping;
mapping.add(Book::isColored, "1234");
mapping.add(Book::isAvailable, "23498");
mapping.add(Book::isAdults, "0562");
ReaderResponse response = reader.getReaderResponse();
mapping.add((anyBook) -> response == null, "4587");

String chosen = mapping.stream()
        .filter(p -> p.getKey().test(book))
        .map(Pair::getValue)
        .findFirst()
        .orElseGet(response::getName);

或者

mapping.add((anyBook) -> true, response.getName());
mapping.stream()
        .filter(p -> p.getKey().test(book))
        .map(Pair::getValue)
        .findFirst()
        .ifPresent(book::setChose);

这并没有完全实现你的算法(因为有一些歧义)但是演示了使用enum作为策略模式。在这种形式中,add/adjust 代码更容易,因为每种书籍类型的所有特殊功能都在它自己的位置(它自己的 enum)。

请注意,当一本书可以分为多种类型时(例如 Coloured Adult),这也会有所帮助。

enum BookType {
    Coloured("1234"),
    Available("23498"),
    Adult("0562");

    private final String chosen;

    BookType(String chosen) {
        this.chosen = chosen;
    }

    public String getChosen() {
        return chosen;
    }

}

class Book {
    final Set<BookType> types = EnumSet.noneOf(BookType.class);
    Book book;

    public boolean hasType(BookType type) {
        return types.contains(type);
    }

    public void setChosen(String s) {

    }
}

public void saveContent() throws Exception {
    for(BookType type: BookType.values()) {
        if(book.hasType(type)) {
            book.setChosen(type.getChosen());
        }
    }
}