繁体   English   中英

参数的Java模式只有一个需要非空?

[英]Java pattern for parameters of which only one needs to be non-null?

在上一次我经常编写具有多个参数但仅使用其中一个参数的长函数,并且功能仅在散布在函数周围的几个关键点上不同。 因此,拆分函数会在没有目的的情况下创建太多小函数。 这是好风格还是有一个很好的一般重构模式? 更清楚,一个例子:

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,如果两者都是非空的话会发生什么)但是我不想写4个单独的函数......我知道这可能太笼统但也许有人对这个问题原则有一般解决方案:-)

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

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

我认为你应该使用像这样的行为模式

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

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

你能用这样的东西吗?

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

期望空值是一种反模式,因为它会使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();
}

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM