ng tableName, List<String> rowKeyList,
String cfName, List<String> columns,
boolean allowNull) throws Exception {
HTable table = getHtable(tableName);
final String cf = (cfName == null) ? "cf" : cfName;
List<Get> gets = rowKeyList.stream().map(
rowKey -> {
String rowKeyNotEmpty = (rowKey == null ? "null" : rowKey);
Get get = new Get(Bytes.toBytes(rowKeyNotEmpty));
if (columns != null && !columns.isEmpty()) {
for (String col: columns) {
get.addColumn(Bytes.toBytes(cf), Bytes.toBytes(col));
}
}
return get;
}
).collect(Collectors.toList());
Result[] results = table.get(gets);
logger.info("Got {} results from hbase table {}. cf: {}, columns: {}", results.length, tableName, cf, columns);
List<Result> rsList = new ArrayList<>();
for (int i = 0; i < rowKeyList.size(); i++) {
if (!allowNull && isResultEmpty(results[i])) {
logger.warn("cant't get record for rowkey:{}", rowKeyList.get(i));
continue;
}
rsList.add(results[i]);
}
logger.info("got {} rows from table {} with {} rowkeys", rsList.size(), tableName, rowKeyList.size());
return rsList;
}
这段代码有大部分代码惯有的毛病:多个逻辑混杂在一起;大量条件性的业务逻辑中间藏有一小段外部依赖的调用(HTable table = getHtable(tableName); Result[] results = table.get(gets); 访问 Hbase数据源),而这一小段外部依赖使得整个方法的单测编写变得麻烦了。 在 “使用Java函数接口及lambda表达式隔离和模拟外部依赖更容易滴单测” 一文中已经指出,只要使用一个 BiFunction 来模拟 Result[] results = table.get(gets); 这段调用,即可使得 getRows 整个方法变成纯函数。 不过,这个方法已经有好几个参数了,再增加一个参数会比较难看。可以应用参数对象模式,将多个紧密关联的原子参数聚合为一个参数对象。注意到 htableName,rowkeyList, cf, columns, allowNull 确实是从Hbase获取数据所需要的紧密关联的参数聚合,因此适合参数对象模式。重构后代码如下所示:
public List<Result> getRows(String tableName, List<String> rowKeyList,
String cfName, List<String> columns,
boolean allowNull) throws Exception {
return getRows(
new HbaseFetchParamObject(tableName, rowKeyList, cfName, columns, allowNull),
this::getFromHbase
);
}
private Result[] getFromHbase(String tableName, List<Get> gets) {
try {
HTable table = getHtable(tableName);
return table.get(gets);
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
throw new RuntimeException(ex);
}
}
public List<Result> getRows(HbaseFetchParamObject hbaseFetchParamObject,
BiFunction<String, List<Get>, Result[]> getFromHbaseFunc) throws Exception {
String tableName = hbaseFetchParamObject.getTableName();
String cfName = hbaseFetchParamObject.getCfName();
List<String> rowKeyList = hbaseFetchParamObject.getRowKeyList();
List<String> columns = hbaseFetchParamObject.getColumns();
boolean allowNull = hbaseFetchParamObject.isAllowNull();
String cf = (cfName == null) ? "cf" : cfName;
List<Get> gets = buildGets(rowKeyList, cf, columns);
Result[] results = getFromHbaseFunc.apply(tableName, gets);
logger.info("Got {} results from hbase table {}. cf: {}, columns: {}", results.length, tableName, cf, columns);
List<Result> rsList = buildResult(rowKeyList, results, allowNull);
logger.info("got {} rows from table {} with {} rowkeys", rsList.size(), tableName, rowKeyList.size());
return rsList;
}
private List<Get> buildGets(List<String> rowKeyLis