前言
在业务开发过程中,免不了使用if、else、switch来处理不同的业务逻辑。而一但业务比较复杂,代码里面就充斥了大量的逻辑分支判断,导致代码臃肿不堪,及不好维护。所以,今天这篇文章我们就来聊一聊,如何使用策略模式,让你的代码变得更加的优雅。
一、策略模式的定义?
定义一系列算法,封装每个算法,并使他们可以互换,不同的策略可以让算法独立于使用它们的客户而变化
简单来说,策略模式就是把ifelse的行为抽象出来一个策略接口,每一种行为对应一个策略。在具体业务环境中仅持有该策略接口,根据不同的场景使用不同的实现类即可。结构图如下:
二、使用案例
1.业务背景
项目里有个发送微信模版消息的需求,有直播消息推送、学情消息推送、提交提醒消息推送等不同的业务类型,不同的类型需要发送不同的模版消息。
2.使用策略模式
2.1 定义一个策略接口
定义一个策略接口,定义好业务消息类型都需要用到的公用方法
public interface WxTemplateMsgStrategyService {
/**
* 获取消息类型
* @return void
**/
String getMsgType();
/**
* 保存待发送的微信消息
* @param vo
* @return void
**/
void saveWxMsgWait(WxMsgDataVO vo);
/**
* 组装发送微信消息
* @param waitPush
* @return void
**/
WxMpTemplateMessage convertWxMsgData(WxTemplateMsgWaitPush waitPush);
}
2.2 定义各种策略
定义消息类型策略,直播消息通知、学情推送、提交提醒等实现类都实现这个接口,实现类里面就可以实现具体的业务了。由于是真实项目,这里就不贴出具体实现业务的代码,用伪代码代替了。
直播通知实现
@Slf4j
@Service
public class WxLiveMsgStrategyServiceImpl implements WxTemplateMsgStrategyService{
@Override
public String getMsgType() {
return BelongTypeEnum.ZB.getName();
}
@Transactional(rollbackFor = Exception.class)
@Override
public void saveWxMsgWait(WxMsgDataVO vo) {
//执行保存直播通知的相关方法
}
@Override
public WxMpTemplateMessage convertWxMsgData(WxTemplateMsgWaitPush waitPush) {
//执行组装发送直播通知消息的相关方法
}
}
学情通知实现
@Slf4j
@Service
public class WxStudyMsgStrategyServiceImpl implements WxTemplateMsgStrategyService {
@Override
public String getMsgType() {
return BelongTypeEnum.XQ.getName();
}
@Transactional(rollbackFor = Exception.class)
@Override
public void saveWxMsgWait(WxMsgDataVO vo) {
//执行保存学情通知的相关方法
}
@Override
public WxMpTemplateMessage convertWxMsgData(WxTemplateMsgWaitPush waitPush) {
//执行组装发送学情通知的相关方法
}
}
提醒通知实现
@Service
public class WxGraduationMsgStrategyServiceImpl implements WxTemplateMsgStrategyService {
@Override
public String getMsgType() {
return BelongTypeEnum.LW.getName();
}
@Transactional(rollbackFor = Exception.class)
@Override
public void saveWxMsgWait(WxMsgDataVO vo) {
//执行保存提醒通知的相关方法
}
@Override
public WxMpTemplateMessage convertWxMsgData(WxTemplateMsgWaitPush waitPush) {
//执行组装发送提醒通知消息的相关方法
}
}
2.3 使用策略
有的文章使用了枚举、HashMap 的方式来根据策略名称映射策略实现类 ,这样是没有问题。我并没有像策略模式结构图中那样新建一个 Context 类持有策略接口,那是标准的策略模式,其实道理是一样的,关键是怎么调用策略。我这里是直接使用 Bean来调用,这样更贴近业务。
@Override
public String initWxMsgWait(WxMsgDataVO vo) {
WxTemplateMsgStrategyService businessBean = getBusinessBean(vo.getBelongType().getName());
log.info("=========获取到的bean是:========="+ businessBean);
if (businessBean == null) {
return "业务对象不存在";
}
businessBean.saveWxMsgWait(vo);
return null;
}
@Override
public WxMpTemplateMessage convertWxMsgData(WxMsgDataVO vo) {
WxTemplateMsgStrategyService businessBean = getBusinessBean(vo.getBelongType().getName());
log.info("=========获取到的bean是:========="+ businessBean);
if (businessBean != null) {
return businessBean.convertWxMsgData(vo.getWaitPush());
}
return null;
}
private WxTemplateMsgStrategyService getBusinessBean(String msgType) {
if (StringUtils.isNotBlank(msgType)) {
//获取所有实现该策略接口的bean
List<WxTemplateMsgStrategyService> maintenanceBeans = SpringContextKit.getBeans(WxTemplateMsgStrategyService.class);
if (CollUtil.isNotEmpty(maintenanceBeans)) {
for (WxTemplateMsgStrategyService bean : maintenanceBeans) {
if (msgType.equals(bean.getMsgType())) {
return bean;
}
}
}
}
return null;
}
3.使用对比
未使用策略模式的时候,所有的通知类型实现都在一个类里面,导致代码又长又不好阅读,若再新加一个通知类型的需求,则需在该类里面在添加一个判断类型的分支,实现相关业务,不易扩展;
使用策略模式后,代码变得更简洁,若有新的通知类型也更加容易扩展;
三、策略模式的优缺点
优点:
- 1、可以避免多重条件选择语句,减少繁琐的 if、switch 判断逻辑。
- 2、符合开闭原则,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
- 3、代码优雅、可复用、可读性好。
缺点:
- 1、策略如果很多的话,会产生很多策略类,造成策略类膨胀。
- 2、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
总结
好了,以上就是今天要讲的内容。本文通过一个实例介绍了策略模式的使用,具体应用到项目中还需要视情况而定,不能一味的追求设计,过度设计,否则适得其反。感谢大家的阅读,若觉得对你有帮助的话,动动小手,还不忘点赞评论支持一波哟,你的支持是我最大的动力~