前言:最近刚完成一个专项的代码codeing,今天花了一下午把代码优化了下,总结了一些优化时用到的思想和方法,后续也会继续补充好的代码习惯和最佳范式
策略模式
自我介绍
策略这个词应该怎么理解,打个比方说,我们出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。再比如我们去逛商场,商场现在正在搞活动,有打折的、有满减的、有返利的等等,其实不管商场如何进行促销,说到底都是一些算法,这些算法本身只是一种策略,并且这些算法是随时都可能互相替换的,比如针对同一件商品,今天打八折、明天满100减30,这些策略间是可以互换的。
策略模式(Strategy),定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。通常策略模式的实现需要有Context+Strategy+ConcreteStrategy三部分组成,其中,Context是上下文,维护一个对Strategy对象的引用,在此处起到一个工厂模式的作用;Strategy是策略类,用于定义所有支持算法的公共接口;ConcreteStrategy是具体策略实现类,封装了具体的算法或行为,继承于Strategy。UML结构图如下:
策略模式的优点有 1.算法可以自由切换 2.避免使用多重条件判断 3.扩展性良好。缺点是 1.策略类会增多 2.所有策略类都需要对外暴露。
应用场景
通常 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。在本次codeing的代码中,需要对商品在es中进行各种条件下的搜索返回结果,比如:在首页需要展示出特价商品和高频商品和根据登录人ip推荐的特色商品,在商品搜索页又需要有丰富的条件检索,还需要支持用户通过日历查看低价商品等功能。在刚开始写代码时,想把各种搜索条件写在一个方法里,统一管理,做到高内聚低耦合,也方便与之后更改条件,结果第一版就写成了
public BoolQueryBuilder getBoolQueryBuilder(int type, Map<String,Object> params){
if{
// 获取首页商品分类搜索条件的实现
return BoolQueryBuilder;
}else if(type == 1){
// 获取首页特价商品搜索条件的实现
return BoolQueryBuilder;
}else if(type == 2){
// 获取首页推荐商品搜索条件的实现
return BoolQueryBuilder;
}else if(type == 3){
// XXX具体实现
return BoolQueryBuilder;
}else if(type == 4){
// XXX具体实现
return BoolQueryBuilder;
}else if(type == 5){
// XXX具体实现
return BoolQueryBuilder;
}else if(type == 6){
// XXX具体实现
return BoolQueryBuilder;
}
return null;
}
看到这段代码,大家有什么反应呢?
- 不知道具体1、2、3、4、5、6代表什么,调用时传参不明确。哪怕注释写完整,写了枚举,翻阅代码时也很懵,不便于阅读。
- 不方便扩展,扩展时要再加一个else if
- 由于不同的搜索算法入参不同,所以这里使用了Map<String,Object>来接收,也是比较鸡肋。
实现
开始优化这块代码,根据上面策略模式的思想,首先创建了一个搜索条件策略接口类BoolQueryBuilderStrategy,又根据不同的搜索条件,创建了多个实现类,首页商品分类的搜索条件实现类、商品搜索列表的条件实现类、首页推荐商品的条件实现类等等。在这里我没有写工厂类,而是在每个搜索条件实现类中,通过静态内部类和公共的getInstance()方法,实现了单例对象的获取。
- 获取搜索条件策略接口
public interface BoolQueryBuilderStrategy<T> {
/**
* 获取es搜索条件
*
* @param parameter T
* @return BoolQueryBuilder
*/
BoolQueryBuilder getBoolQueryBuilder(T parameter);
}
- 商品搜索条件实现类
public class QueryProductListBoolQueryBuilder implements BoolQueryBuilderStrategy<EsQueryBO> {
// 无参构造器
private QueryProductListBoolQueryBuilder() {
}
@Override
public BoolQueryBuilder getBoolQueryBuilder(EsQueryBO queryBuilderBO) {
// 获取商品列表搜索条件
return FreightChargeQueryBuilder.builder()
// 商品类型
.guideUseType(UseTypeEnum.GENERAL.getCode())
// 起运港
.fromTerminalId(queryBuilderBO.getFromTerminalIds())
// 目的港
.toTerminalId(queryBuilderBO.getToTerminalIds())
// 有效期
.validTo()
// etd
.etdTime(queryBuilderBO.getReqDTO().getEtdDate())
// 其他条件
...
.build();
}
/**
* 获取实例
*
* @return 单例对象
*/
public static QueryProductListBoolQueryBuilder getInstance() {
return QueryProductListBoolQueryBuilder.InnerClass.INSTANCE;
}
/**
* 静态内部类
*/
private static class InnerClass {
private static QueryProductListBoolQueryBuilder INSTANCE = new QueryProductListBoolQueryBuilder();
}
}
3.使用
...
// 构建查询 Builder
EsQueryBO queryBO = EsQueryBO.builder().fromTerminalIds(fromTerminalIds).toTerminalIds(toTerminalIds).reqDTO(reqDTO).build();
BoolQueryBuilder boolQueryBuilder = QueryProductListBoolQueryBuilder.getInstance().getBoolQueryBuilder(queryBO);
...