h1.背景
在攻略全文搜索中,搜索的接口很丰富,并且将来可能会增加更多的需求。搜索业务类提供的接口既要能满足将来的扩展,
又不能暴露底层的细节,还要避免功能组合带来接口的膨胀。
h1.设计方法
搜索接口的依赖关系,如下图:
前端控制器 ----> 搜索业务方法 --> QP搜索API
QP主要需要一下参数控制搜索条件:
普通的: key=key
指定字段搜索: search_in=field
按照月份过滤: travelmonths=month
飘红: hl=true,hl.fl=highlightFields,
hl.simple.pre=飘红开始标签
hl.simple.post=飘红结束标签
h2.不好的设计1
如果Service层像控制器层提供一个functionParams,让Controller根据
不同的情景设置不同的参数进行搜索:
这样可以满足接口扩展的功能,但是这样就把控制器层依赖QP的接口参数,qp参数变化会跨层影响控制层。
所以最好再提供一个封装,让QP对于控制器层透明。
h2.不好的设计2
常用的方式,对不同的条件封装出不同的接口,这样可能就会有:
普通的搜索:
同样对于只在作者中搜索:
然后同样会有按照月份过滤:
然后还会有只在作者中搜索并且按照月份过滤...
这样接口就会组合性的增长。
h2.Best practice
比较好的方法是能够抽象出一个动态组合各种功能的东东来搞定这个。
这样我们就可以定义一个接口来搞定所有的需求:
控制器就可以动态的组合各种功能了:
普通带飘红搜索:
复杂一些的搜索: 只在作者中搜索并且按照月份过滤带飘红的搜索
在攻略全文搜索中,搜索的接口很丰富,并且将来可能会增加更多的需求。搜索业务类提供的接口既要能满足将来的扩展,
又不能暴露底层的细节,还要避免功能组合带来接口的膨胀。
h1.设计方法
搜索接口的依赖关系,如下图:
前端控制器 ----> 搜索业务方法 --> QP搜索API
QP主要需要一下参数控制搜索条件:
普通的: key=key
指定字段搜索: search_in=field
按照月份过滤: travelmonths=month
飘红: hl=true,hl.fl=highlightFields,
hl.simple.pre=飘红开始标签
hl.simple.post=飘红结束标签
h2.不好的设计1
如果Service层像控制器层提供一个functionParams,让Controller根据
不同的情景设置不同的参数进行搜索:
public SearchBookBean searchBooks(String key, Map<String,Object> functionParams)
这样可以满足接口扩展的功能,但是这样就把控制器层依赖QP的接口参数,qp参数变化会跨层影响控制层。
所以最好再提供一个封装,让QP对于控制器层透明。
h2.不好的设计2
常用的方式,对不同的条件封装出不同的接口,这样可能就会有:
普通的搜索:
public SearchBookBean searchBooks(String key, boolean highlight){
//1.根据普通搜索需要的参数设置到functionParams
Map<String, Object> functionParams = new HashMap<String,Object>();
if(highlight){
addhighlightParams(functionParams);
}
//2.调用public SearchBookBean searchBooks(String key, Map<String,Object> functionParams)
return searchBooks(key,functionParams);
}
同样对于只在作者中搜索:
public SearchBookBean searchBooksOnlyUserName(String key, boolean highlight){
Map<String, Object> functionParams = new HashMap<String,Object>();
if(highlight){
addhighlightParams(functionParams);
}
functionParams.put("search_in", "userName");
return searchBooks(key,functionParams);
}
然后同样会有按照月份过滤:
public SearchBookBean searchBooksWithMonthFilter(String key,int month, boolean highlight){
//...
}
然后还会有只在作者中搜索并且按照月份过滤...
这样接口就会组合性的增长。
h2.Best practice
比较好的方法是能够抽象出一个动态组合各种功能的东东来搞定这个。
class SearchFunction {
private Map<String,Object> functionParams;
public SearchFunction(){
functionParams = new HashMap<String, Object>();
}
public SearchFunction withOnlyUserName(){
functionParams.put("search_in", "userName");
return this;
}
public SearchFunction withMonthFilter(int month){
functionParams.put("travelmonths", month);
return this;
}
public SearchFunction withDefaultHighlight(){
List<String> highlightFields = new ArrayList<String>();
highlightFields.add("title");
highlightFields.add("travelRoute");
highlightFields.add("destCities");
return withHighlight(highlightFields);
}
public SearchFunction withHighlight(List<String> highlightFields){
functionParams.put("hl", true);
functionParams.put("hl.fl", StringUtils.join(highlightFields,','));
functionParams.put("hl.simple.pre", "<span class=\"colOrange\">");
functionParams.put("hl.simple.post","</span>");
return this;
}
public Map<String,Object> getFunctionParams(){
return functionParams;
}
}
这样我们就可以定义一个接口来搞定所有的需求:
public SearchBookBean searchBooks(String key, SearchFunction function){
Map<String, Object> functionParams = null;
if(function == null){
functionParams = new HashMap<String,Object>();
}else{
functionParams = function.getFunctionParams();
}
return searchBooks(key, functionParams);
}
控制器就可以动态的组合各种功能了:
普通带飘红搜索:
SearchFunction sf = new SearchFunction();
sf.withDefaultHighlight();
SearchBookBean searchBean = service.searchBooks("keyword", sf);
复杂一些的搜索: 只在作者中搜索并且按照月份过滤带飘红的搜索
SearchFunction sf = new SearchFunction();
sf.withOnlyUserName().withMonthFilter(1).withDefaultHighlight();
SearchBookBean searchBean = service.searchBooks("keyword", sf);