一、前言
在互联网打工的小伙伴可能都开发都开发过管理类的系统吧,这样的系统都有一个特点——查询条件贼多,而且每个条件都需要推荐搜索(也就是下图的下拉选择)。
小白: 这也太麻烦了,搞这么花里呼哨干啥呀,直接输入模糊搜索不就完事了。
leader: 心想这小伙太年轻了。模糊搜索效率太差啦,而且这样模糊搜索不走索引,条件一多,业务是不是又要吐槽系统* *了😄。我们使用推荐搜索的好处就是把模糊搜索消耗的性能平均到各个搜索条件,这样我们一点查询按钮不就精确查询了,这一下查询速度是不是可以飞起了!
小白: 是哦,用户体验又上升了一个等级!
咱作为一名有工匠精神的攻城狮,细节这块那必须拿捏呀😎
这么多个搜索条件,很多小伙伴直接区分一下类型if-else简单高效完成需求。
开发一时爽,重构就要哭了。
面对这么多if-else的场景,又是个提升代码b格的好机会了,运用策略模式再合适不过了,工厂模式更倾向于创建型!
二、原理
下面带大家使用策略模式完成此次需求。运用知识,我们首先要掌握这个思想的核心,接下来我们看一下结构图。
抽象策略类: 定义规则,也就是策略逻辑的入口
策略类:抽象策略类的子类(具体实现)
策略上下文:存放和执行具体逻辑类的地方
其实也不复杂对吧,大家一看就懂了,接下来带大家一起看一下案例。
三、案例
/**
* 推荐搜索抽象策略类
*/
public abstract class AbstractSuggestStrategy<T> {
/**
* 推荐搜索策略
* @param suggestParam 其中包含了策略类型和搜索关键字
* @return
*/
public abstract T suggest(SuggestParam suggestParam);
}
我们先定义抽象策略类,给具体的策略类制定了规则,同时对我们后面自动装配上下文也是关键性的作用。
然后就是具体策略类了。
/**
* 订单简称suggest策略搜索类
*/
@Service
@SuggestType(type = SuggestTypeEnum.ORDER_NAME)
public class OrderNameSuggestStrategy extends AbstractSuggestStrategy<T> {
@Override
public T suggest(SuggestParam suggestParam) {
// 具体查询逻辑
return null;
}
}
/**
* 客户名称suggest策略搜索类
*/
@Service
@SuggestType(type = SuggestTypeEnum.CUSTOMER_NAME)
public class CustomerNameSuggestStrategy extends AbstractSuggestStrategy<T> {
@Override
public T suggest(SuggestParam suggestParam) {
// 具体查询逻辑
return null;
}
}
最后就是定义一个策略上下文
@Component
public class StrategyContext {
// 这个就是自动装配上下文的关键功能,这就利用到Spring注解的List特殊注入功能。
// 继承AbstractSuggestStrategy抽象类并且被spring管理的类都会被加载到这个list。
@Resource
private List<AbstractSuggestStrategy> suggestStrategies;
private static Map<SuggestTypeEnum, AbstractSuggestStrategy> suggestStrategyMap = Maps.newHashMap();
/**
* 初始化
*/
@PostConstruct
public void init() {
if (CollectionUtil.isEmpty(suggestStrategies)) {
return;
}
// 遍历list, 构造类型和具体被spring管理类的映射关系
suggestStrategies.forEach(strategy -> {
SuggestType suggestType = AopUtils.getTargetClass(strategy).getAnnotation(SuggestType.class);
suggestStrategyMap.put(suggestType.type(), strategy);
});
}
/**
* 根据枚举类型获取对应被spring管理的策略类
* @param suggestType
* @return
*/
public static AbstractSuggestStrategy getStrategy(StoreSuggestTypeEnum suggestType) {
AbstractSuggestStrategy suggestStrategy = suggestStrategyMap.get(suggestType);
if (null == suggestStrategy) {
throw new IllegalArgumentException("not fond suggestType");
}
return suggestStrategy;
}
}
其实这边就是多做了一步,让策略类交由spring管理,并且建立映射关系,我们通过key去获取对应的策略类。
因为在开发中我们项目基本上都是基于spring的,策略类查询逻辑正常也是需要依赖spring管理类,所以统一起来就可以更便捷的开发。
然后就可以在业务逻辑去获取上下文了~
/**
* @Description 推荐搜索业务类
*/
@Slf4j
@Service
public class SuggestBizService {
public Object suggest(SuggestParam suggestParam) {
SuggestTypeEnum suggestTypeEnum = SuggestTypeEnum.findByCode(suggestParam.getSuggestType());
if (suggestTypeEnum == null) {
throw new StoreApiException("请指定正确的查询类型");
}
AbstractSuggestStrategy suggestStrategy = StrategyContext.getStrategy(suggestTypeEnum);
return suggestStrategy.suggest(suggestParam);
}
}
贴心的rose也给大家贴上面实现的其他代码~
/**
* @Description 推荐搜索入参
*/
@Data
@EqualsAndHashCode
@Accessors(chain = true)
public class SuggestParam implements Serializable {
@ApiModelProperty(value = "suggest类型 ORDER_NAME:订单名称, CUSTOMER_NAME:客户名称", required = true)
private String suggestType;
@ApiModelProperty(value = "suggest关键字")
@NotBlank(message = "suggest关键字不可为空")
@Length(max = 50, message = "关键字小于50个字")
private String keyword;
}
/**
* @Description 策略类型注解
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SuggestType {
SuggestTypeEnum type();
}
/**
* @Description suggest接口数据类型定义
*/
@Getter
@AllArgsConstructor
public enum SuggestTypeEnum {
ORDER_NAME("ORDER_NAME", "订单名称"),
CUSTOMER_NAME("CUSTOMER_NAME", "客户名称");
private final String code;
private final String name;
public static SuggestTypeEnum findByCode(String code) {
for (SuggestTypeEnum typeEnum : values()) {
if (typeEnum.getCode().equals(code)) {
return typeEnum;
}
}
return null;
}
}
是不是也不复杂哈哈~
其实策略模式的核心思想就是根据不同的类型去实现不同的策略。
四、总结
通过策略设计模式的使⽤可以把我们⽅法中的if-else语句优化掉,⼤量的if-else语句使⽤会让代码难以扩展,也不好维护,同时在后期遇到各种问题也很难维护。在使⽤这样的设计模式后可以很好的满⾜隔离性与和扩展性,同时类的职责也单一了,对于不断新增的需求也⾮常⽅便承接。
设计模式其实是前辈们开发中总结的一下通用范式,我们要合理的学习每种设计模式适合场景,解决什么问题。也不要因设计模式而在写代码时强行使用。
在面对各种各样的开发场景,我们要多思考,多沉淀,才可以让自己的代码更优雅,更好扩展。
加油打工人!奥利给😎
我是rose,感谢各位的观看,各位的点赞就是rose输出的最大动力,我们下篇文章见!