清洁方式,以避免条件

时间:2018-05-20 07:27:49

标签: java if-statement coding-style conditional-statements

我有这样的代码:

 Map<String, String> args = new HashMap<>();

    args.put("-T", "Tom Sawyer");
//        args.put("-I", "1112223334");

    if (args.containsKey("-T")) {
        Book book = libraryService.findBookByTitle(args.get("-T"));
    } else {
        Book book = libraryService.findBookByIsbn(args.get("-I"));                       
    }  

LibraryService:

public class LibraryService {

    private final BookRepository bookRepository = new BookRepository();

    public Book findBookByTitle(String title) {
        return bookRepository.findByTitle(title);
    }

    public Book findBookByIsbn(String isbn) {
        return bookRepository.findByIsbn(isbn);
    }

BookRepository:

public class BookRepository {

 private List<Book> books = new ArrayList<>();

  public Book findByIsbn(String isbn) {
        return books.stream()
            .filter(s -> s.getIsbn().equals(isbn))
            .findFirst()
            .orElseThrow(() -> new RuntimeException(NO_BOOKS_FOUND));
}

    public Book findByTitle(String title) {
        return books.stream()
            .filter(s -> s.getTitle().equals(title))
            .findFirst()
            .orElseThrow(() -> new RuntimeException(NO_BOOKS_FOUND));
}

有没有一种干净的方法来避免ifs?我希望我的代码决定是否必须使用参数-I-T。我处理args没有任何情况时的情况,我只是简化了StackOverflow的代码。我在代码中多次使用findByTitle和findByIsbn方法,所以我不确定另一种方法是否适合这里。

4 个答案:

答案 0 :(得分:3)

不是将参数传递给存储库,而是将完整的Predicate传递给它:

public class findOneByPredicate(Predicate<Book> filter) {
        return books.stream()
            .filter(filter)
            .findFirst()
            .orElseThrow(() -> new RuntimeException(NO_BOOKS_FOUND));
}

然后你可以这样称呼它:

findOneByPredicte(b -> b.getIsbn().equals("ISBN"));

答案 1 :(得分:2)

实际上,代码似乎是最简单的,可能是最好的形式。

但是,您可以使用“书籍查找器”的映射来删除显式的if块。这是使用供应商的一个版本:

Map<String, Function<String, Book>> resolvers = new HashMap<>();
resolvers.put("-T", libraryService::findBookByTitle);
resolvers.put("-I", libraryService::findBookByIsbn);

然后可以在所有可能键的短流中使用:

Book book = Stream.of("-T", "-I").filter(args::containsKey)
                  .findFirst()
                  .map(key -> resolvers.get(key).apply(args.get(key)))
                  .orElse(null);

如果地图中既不null也不-T,则上述内容将返回-I

答案 2 :(得分:1)

你的代码看起来很不错,至少对我而言。

您的if语句不需要删除。它们没有重复,所以请保留它们。

另一方面,我确实在findBy方法中找到了一些重复的代码:

public Book findByIsbn(String isbn) {
    return books.stream()
        .filter(s -> s.getIsbn().equals(isbn))
        .findFirst()
        .orElseThrow(() -> new RuntimeException(NO_BOOKS_FOUND));
}

public Book findByTitle(String title) {
    return books.stream()
        .filter(s -> s.getTitle().equals(title))
        .findFirst()
        .orElseThrow(() -> new RuntimeException(NO_BOOKS_FOUND));
}

您可以编写一个名为findBy的新方法:

private Book findBy<T>(Function<Book, T> selector, T value) {
    return books.stream()
        .filter(s -> selector.apply(s).equals(value))
        .findFirst()
        .orElseThrow(() -> new RuntimeException(NO_BOOKS_FOUND));
}

然后让findByIsbnfindByTitle致电findBy

public Book findByIsbn(String isbn) {
    return findBy(Book::getIsbn, isbn);
}

public Book findByTitle(String title) {
    return findBy(Book::getTitle, title);
}

答案 3 :(得分:0)

你可以摆脱两个组合模式的if。我还认为第一个块中的if与其周围的代码有些不同。另一个问题是,这不符合开放式原则。让我们说你想要另一种类型的搜索参数,如registernumber -R或其他什么。你必须触摸if语句,如果这变得越来越大,你可能会破坏一些东西。

所以让我们看看,如果没有

,那么很好的代码会是什么样子
args.put("-T", "Tom Sawyer");
args.put("-I", "1112223334");
Book book = libraryService.findBook(args);

但这明显不适合开箱即用。但你可以用策略模式做类似的事情。

IBookFindStrategy {
   Book findBook(string param)
}

class IsbnFindStrategy : IBookFindStrategy {
   Book findBook(string param) {
      // your repocall
   }
}

class NameFindStrategy : IBookFindStrategy {
   Book findBook(string param) {
      // your repocall
   }
}

现在您只需要在其他地方转换参数并在Factory中初始化正确的策略。 Factory可以将参数存储在Hashmap中,并使用param -T调用它,它将为您提供NameFindStrategy。像这样的东西

class StrategyFactory {
      Hashtable<String, IBookFindStrategy > strategies;

      public StrategyFactory() {
          strategies = new HashMap<String, IBookFindStrategy >();
          strategies.put("-T", new NameFindStrategy());
          strategies.put("-I", new NameIsbnFindStrategy());
      }

      public IBookFindStrategy GetStrategy(string param) {
          return strategies.get(param);
      }
}

最后,你的主要看起来像这样:

StrategyFactory factory = new StrategyFactory();
IBookFindStrategy bookFinder = factory.getStrategy(args);
Book book = bookFinder.findBook(args);

我不是一个开发机器,我的java有点生疏,所以我有点懒,不能写下所有内容,但我希望你能得到这个概念。