【问题标题】:Refactoring the code of many similar methods重构很多类似方法的代码
【发布时间】:2018-04-16 07:54:59
【问题描述】:

您好,我的代码中有许多类似的方法,如下所示,也许我将来会有更多。

public void getParticularBook(String nameOfBook){
    String bookDetails = "";
    Iterator<Book> iterator = allBooks.iterator();
    while(iterator.hasNext()) {
        Book b = iterator.next();
        if(b.getTitle().equalsIgnoreCase(nameOfBook)){
            bookDetails = b.toString();
        }
    }
    System.out.println(bookDetails);
}

public void getBooksDataOnRange(int from, int to){
    String bookDetails = "";
    Iterator<Book> iterator = allBooks.iterator();
    while(iterator.hasNext()) {
        Book b = iterator.next();
        if(b.getIssueYear() >= from && b.getIssueYear() <= to){
            bookDetails = b.toString();
        }
    }

    if(bookDetails.isEmpty()){
        System.out.println("No books in range of: " + from + "-" + to);
    }
    System.out.println(bookDetails);
}

public void getBooksDataOnType(String type){
    String bookDetails = "";
    Iterator<Book> iterator = allBooks.iterator();
    while(iterator.hasNext()) {
        Book b = iterator.next();
        if(b.getType().equalsIgnoreCase(type)){
            bookDetails = b.toString();
        }
    }

    if(bookDetails.isEmpty()){
        System.out.println("No books of type: " + type);
    }
    System.out.println(bookDetails);
}

上面的方法是某种过滤器,它们根据例如返回数据。书的类型,书的发行日期。

问题是,是否可以重构所有此类方法的代码?或者也许更好地遵循上述方案? 感谢您的回答

【问题讨论】:

  • 最后两种方法是按预期工作还是只打印出一本书的信息,即使应该打印多本书?
  • 是的,您只能有一个带有 Predicate 类型参数的 getBooksByPredicate 方法。这个特殊的类是在 java 8 中引入的,它表示一个返回布尔值的方法。

标签: java refactoring


【解决方案1】:

你可以创建一个名为getBooksWithPredicate的方法:

public static void getBooksWithPredicate(Predicate<Book> predicate, String errorMessage) {
    String bookDetails = "";
    Iterator<Book> iterator = allBooks.iterator();
    while(iterator.hasNext()) {
        Book b = iterator.next();
        if(predicate.test(b)){
            bookDetails = b.toString();
        }
    }

    if(bookDetails.isEmpty()){
        System.out.println(errorMessage);
    }
    System.out.println(bookDetails);
}

这基本上是所有三种方法的概括。然后可以通过调用这个方法来实现这三个方法:

public void getParticularBook(String nameOfBook){
    getBooksWithPredicate(b -> b.getTitle().equalsIgnoreCase(nameOfBook), "");
}

public void getBooksDataOnRange(int from, int to){
    getBooksWithPredicate(b -> b.getIssueYear() >= from && b.getIssueYear() <= to, "No books in range of: " + from + "-" + to);
}

public void getBooksDataOnType(String type){
    getBooksWithPredicate(b -> b.getType().equalsIgnoreCase(type), "No books of type: " + type);
}

【讨论】:

    【解决方案2】:

    您的问题有多种解决方案。

    对于getParticularBook()方法,你可以有一个单独的HashMap&lt;String,Book&gt;,这样你就不需要每次都遍历所有的书。这只有在没有重复项时才有效。

    对于getBooksDataOnRange() 方法,您可以有一个HashMap&lt;Integer, ArrayList&lt;Book&gt;&gt;,其中整数是年份,ArrayList 将包含该年份出版的书籍列表。如果这里的内存有问题,您可以使用HashMap&lt;Integer, ArrayList&lt;String&gt;&gt;,而不是存储书籍对象,而是存储书籍的名称。可以从之前的 HashMap 中获取 book 对象。

    对于getBooksDataOnType()的方法,我猜实际的需求是获取给定类型的所有书籍的数据。如果一本书可以有多种类型,我会建议HashMap&lt;String, ArrayList&lt;String&gt;&gt;。如果没有,并且内存对您来说不是问题,那么您可以为此使用HashMap&lt;String, ArrayList&lt;Book&gt;&gt;

    这里是指向 HashMap 和 ArrayList 的 Java 文档链接。这将有助于您的实施。

    HashMap:https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html

    数组列表:https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html

    【讨论】:

      【解决方案3】:

      有许多不同的选项可以做到这一点。基本思想是,如果一本书与您的搜索匹配,则将书籍的迭代与测试分开。

      例如某种命令模式并传递一个比较两本书的方法:

      public void getBooks(Book testAgainst, Comparator<Book> comparator){
      iterate
      comparator.compare(bookFromIterator, testAgainst);
      print result if matches  
      }
      

      然后您可以将不同的比较器传递给该方法 - 例如标题比较器、年份比较器等。

      另一种(也是更好的)方法是查看 Hibernate 如何查询数据。创建类似“BookSearchCriteria”类的东西。比如:

      class BookSearchCriteria {
        int fromYear;
        int toYear;
        String title;
      
        public boolean matches(Book book){
              ... test for title, test for year etc...
         }
      }
      

      你的方法会变成:

      public void getBooks(BookSearchCriteria  criteria){
      iterator
      ....
      if(criteria.matches(book)) then do stuff
      }
      

      这将是一个更好的例子,因为您可以通过多种方式扩展该标准 - 例如组合属性,使其成为 AND 或 OR 标准等。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多