【问题标题】:Clean way to avoid conditions避免条件的清洁方法
【发布时间】:2018-10-30 03:39:15
【问题描述】:

我有这样的代码:

 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"));                       
    }  

图书馆服务:

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);
    }

书库:

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 方法,所以我不确定其他方法是否适合这里。

【问题讨论】:

  • 能否多发些代码,尤其是代码重复的地方,让我们看看如何改进?
  • 为了避免每次使用都重复 if,您可以将条件逻辑放在一个函数中。
  • @Sweeper 我发布了更多代码
  • 我还是不明白你想如何改进你的代码。看起来不错。
  • args 来自哪里?我想知道你为什么把它放到地图中

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


【解决方案1】:

不要将参数传递给存储库,而是将完整的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"));

【讨论】:

    【解决方案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);
    

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

    【讨论】:

      【解决方案3】:

      至少在我看来,您的代码看起来不错。

      您的 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);
      }
      

      【讨论】:

        【解决方案4】:

        你可以用两个组合模式摆脱 if 。我还认为第一个块中的 if 与它周围的代码在抽象级别上有些不同。另一个问题是,这不遵循开闭原则。假设您想要另一种类型的搜索参数,例如 registernumber -R 或其他。您将不得不触摸 if 语句,如果它变得越来越大,您可能会破坏某些东西。

        让我们看看,没有 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 可以将参数存储在 Hashmap 中,并使用参数-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);
              }
        }
        

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

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

        我不在开发机器上,我的 java 有点生锈,所以我有点懒得把所有东西都写下来,但我希望你能明白这个概念。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-04-23
          • 1970-01-01
          • 1970-01-01
          • 2011-06-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多