最近来了新公司,主要用到了ElasitcSearch,大家都知道在底层查询代码中往往需要判断传入某个参数是否为空来判断设置查询,例如下方代码:
BoolQueryBuilder query = QueryBuilders.boolQuery();
if (param.getMusicId() != null) {
query.must(QueryBuilders.termQuery("musicId", keyword));
}
if (param.getMusicName() != null) {
query.must(QueryBuilders.matchQuery("musicName", keyword));
}
if (param.getTags() != null) {
query.must(QueryBuilders.termsQuery("tag", tags));
}
//..... 就这样N多if
以上情况一出现后,就导致了下次其他通知开发相关功能的时候,可能不符合他要求,他就会重新拷贝一份,然后再增加或者删除冗余一份出来满足自己需求,久而久之就 臃肿 了起来
于是乎我想到了学习的设计模式 策略模式 又想到了 Java8 Function ,当Function仅支持一个入参,于是我搜了下还有个BiFunction支持两个入参,
我打算将字段定义为策略Key,值就是Function,将查询构建代码抽离主逻辑,不多BB,直接上代码:
private static Map<MusicFieldEnum, BiFunction<BoolQueryBuilder, Object, QueryBuilder>> fieldQueryFunMap;
static {
fieldQueryFunMap = new HashMap<>();
fieldQueryFunMap.put(SHEET, (builder, value) -> builder.filter(QueryBuilders.termsQuery(SHEET.getCode(), value)));
fieldQueryFunMap.put(STATUS, (builder, value) -> builder.filter(QueryBuilders.termQuery(STATUS.getCode(), value)));
fieldQueryFunMap.put(MUSIC_ID, (builder, value) -> builder.filter(QueryBuilders.termsQuery(MUSIC_ID.getCode(), value)));
fieldQueryFunMap.put(SYS_TAG, (builder, value) -> builder.filter(QueryBuilders.nestedQuery(SYS_TAG.getCode(),QueryBuilders.termsQuery(SYS_TAG_ID.getCode(), value), ScoreMode.None)));
}
public BoolQueryBuilder getQuery(Param param){
if (CollectionUtils.isEmpty(param.getSheetId())) {
fieldQueryFunMap.get(SHEET).apply(query, param.getSheetId());
}
if (CollectionUtils.isEmpty(param.getTags())) {
fieldQueryFunMap.get(SYS_TAG).apply(query, param.getTags());
}
if (param.getStatus() == ElasticsearchMusicStatuEnum.PUBLISH) {
fieldQueryFunMap.get(STATUS).apply(query, StatusEnum.PUBLISH_SUCCESS.code);
}
}
虽然代码量增加了点点,但我所想要达到的目的就是将字段的查询方式建立一个围栏,达到规范和便于重用。
使用Java8 的Function将查询构建代码单独抽离出来搭配策略模式,便于统一修改,也可以灵活装配,如有做的不当的地方大佬请赐教。