2

上次我经常写长函数,有几个参数,但只使用其中一个,功能只是在散布在函数周围的几个关键点上有所不同。因此,拆分函数会创建太多没有目的的小函数。这是好的风格还是有一个好的通用重构模式?为了更清楚,举个例子:

public performSearch(DataBase dataBase, List<List<String>> segments) {performSearch(dataBase,null,null,segments);}
public performSearch(DataBaseCache dataBaseCache,List<List<String>> segments) {performSearch(null,dataBaseCache,null,segments);}
public performSearch(DataBase dataBase, List<String> keywords {performSearch(dataBase,null,keywords,null);}
public performSearch(DataBaseCache dataBaseCache,List<String> keywords) {performSearch(null,dataBaseCache,keywords,null);}

/** either dataBase or dataBaseCache may be null, dataBaseCache is used if it is non-null, else dataBase is used (slower). */
private void performSearch(DataBase dataBase, DataBaseCache dataBaseCache, List<String> keywords, List<List<String>> segments)
{
 SearchObject search = new SearchObject();
 search.setFast(true);
 ...
 search.setNumberOfResults(25);

 if(dataBaseCache!=null) {search.setSource(dataBaseCache);}
 else                    {search.setSource(dataBase);}

 ... do some stuff ...
 if(segments==null) 
 {
  // create segments from keywords 
  ....
  segments = ...
  }
}

这种代码风格有效,但我不喜欢所有那些 null 参数以及调用这样错误的方法的可能性(两个参数都为 null,如果两者都是非 null 会发生什么)但我也不想编写 4 个单独的函数...我知道这可能太笼统了,但也许有人对这个问题的原则有一个通用的解决方案:-)

PS:我不喜欢拆分一个长函数,如果除了它很长之外没有其他原因(即如果子函数只按该顺序调用并且仅由这个函数调用),特别是如果它们紧密交织并且需要在它们周围传输大量参数。

4

4 回答 4

2

我认为这是非常糟糕的程序风格。尽量避免这样的编码。由于您已经拥有大量此类代码,因此可能很难重构它,因为每个方法都包含自己的逻辑,与其他方法略有不同。顺便说一句,它很难的事实证明这种风格很糟糕。

我认为您应该使用行为模式,例如

  1. 责任链
  2. 命令
  3. 战略
  4. 模板法

这可以帮助您将程序代码更改为面向对象。

于 2012-09-19T13:04:41.630 回答
1

期望空值是一种反模式,因为它会在您的代码中乱扔 NullPointerExceptions 等待发生。使用构建器模式构建SearchObject. 这是你想要的签名,我会让你弄清楚实现:

class SearchBuilder {
   SearchObject search = new SearchObject();
   List<String> keywords = new ArrayList<String>();
   List<List<String>> segments = new ArrayList<List<String>>();

   public SearchBuilder(DataBase dataBase) {}
   public SearchBuilder(DataBaseCache dataBaseCache) {}
   public void addKeyword(String keyword) {}
   public void addSegment(String... segment) {}

   public void performSearch();
}
于 2012-09-19T13:19:33.083 回答
1

你能用这样的东西吗

public static <T> T firstNonNull(T...parameters) {
    for (T parameter: parameters) {
        if (parameter != null) {
            return parameter;
        }
    }
    throw new IllegalArgumentException("At least one argument must be non null");
}

它不会检查多个参数是否不为空并且它们必须属于同一类型,但您可以像这样使用它:

search.setSource(firstNonNull(dataBaseCache, database));
于 2012-09-19T13:01:53.083 回答
0

我同意亚历克斯所说的。在不知道问题的情况下,我会根据示例中的内容推荐以下结构:

public interface SearchEngine {
  public SearchEngineResult findByKeywords(List<String> keywords);
}

public class JDBCSearchEngine {
  private DataSource dataSource;

  public JDBCSearchEngine(DataSource dataSource) {
     this.dataSource = dataSource;
  }

  public SearchEngineResult findByKeywords(List<String> keywords) {
     // Find from JDBC datasource
     // It might be useful to use a DAO instead of datasource, if you have database operations other that searching
  }
}

public class CachingSearchEngine {
  private SearchEngine searchEngine;

  public CachingSearchEngine(SearchEngine searchEngine) {
    this.searchEngine = searchEngine;
  }

  public SearchEngineResult findByKeywords(List<String> keywords) {
    // First check from cache
    ...
    // If not found, then fetch from real search engine
    SearchEngineResult result = searchEngine.findByKeywords(keywords);
    // Then add to cache
    // Return the result
    return result;
  }
}
于 2012-09-19T13:21:16.667 回答