设计模式应用之策略模式
一、实际开发痛点
当业务需求涉及到很多的分支逻辑时,过多的if-else或者过多的switch代码显得很不简洁,而且当我们修改某一分支逻辑时,要改动的很多,比如现在某一分支不要了,就要把这个if条件删除掉,这样是很不好的,这个时候,我们想到了策略模式,替换掉过多的if-else或者switch语句。
二、什么是策略模式
策略这个词应该怎么理解,打个比方说,我们出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。
再比如我们去逛商场,商场现在正在搞活动,有打折的、有满减的、有返利的等等,其实不管商场如何进行促销,说到底都是一些算法,这些算法本身只是一种策略,并且这些算法是随时都可能互相替换的,比如针对同一件商品,今天打八折、明天满100减30,这些策略间是可以互换的。
策略模式(Strategy),定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。
三、实际应用
1、业务场景
现在需要接收来自某系统的回调,消息回调会有很多类型,比如私聊文本消息、私聊图片消息、新好友申请、私聊语音消息等,每一种消息类型,对应不同的逻辑处理,我们最开始是想直接if-else或者switch,走不同的分支逻辑搞定,但是这样扩展性不好,不易维护,这时我们想到了策略模式。
2、定义枚举类
枚举类存放各种回调类型,值代表的是具体实现类的类名,首字母这里小写。通过key就能得到对应的类beaName。
@Getter
public enum MsgCallBackEnum {
//新好友申请
NEWFRIEND_MSG_CALL_BACK(0, "newFriendMsgCallBackHandler"),
//添加好友成功
ADDFRIENDSUCCESS_MSG_CALL_BACK(16, "addfriendSuccessMsgCallBackHandler"),
//私聊文本消息
PRIVATECHATTEXT_MSG_CALL_BACK(5, "privateChatTextMsgCallBackHandler"),
//私聊图片消息
PRIVATECHATIMAGE_MSG_CALL_BACK(6, "privateChatImageMsgCallBackHandler"),
//私聊视频消息
privateChatVIDEO_MSG_CALL_BACK(7, "privateChatVideoMsgCallBackHandler"),
//私聊语音消息
PRIVATECHATVOICE_MSG_CALL_BACK(8, "privateChatVoiceMsgCallBackHandler");
private Integer type;
private String beanName;
MsgCallBackEnum(Integer type, String beanName) {
this.type = type;
this.beanName = beanName;
}
public static String getBeanName(Integer type) throws BusinessException {
for (MsgCallBackEnum msgCallBackStrategyEnum : MsgCallBackEnum.values()) {
if (msgCallBackStrategyEnum.type.equals(type)) {
return msgCallBackStrategyEnum.getBeanName();
}
}
return null;
}
}
3、定义抽象类
抽象类定义抽象方法handler,每一种逻辑处理类只需要继承这个抽象类就可以了。
public abstract class AbstractMsgCallBackHandler {
public final Boolean process(JSONObject json) {
return this.handler(json);
}
/**
* 处理相应逻辑
*
* @param json
* @return
*/
protected abstract Boolean handler(JSONObject json);
}
4、定义实现类
实现类具体处理业务逻辑,继承抽象类
@Component
@Slf4j
public class NewFriendMsgCallBackHandler extends AbstractMsgCallBackHandler {
@Resource
private CommonService commonService;
@Override
protected Boolean handler(JSONObject json) {
JSONObject data = json.getJSONObject("data");
String wId = data.getString("wId");
String v1 = data.getString("v1");
String v2 = data.getString("v2");
Integer type = data.getInteger("scene");
Map<String, Object> param = new HashMap<>();
param.put("wId", wId);
param.put("v1", v1);
param.put("v2", v2);
param.put("type", type);
commonService.commonSendPost(param, UrlConstant.WK_ACCEPTUSER_URL);
return Boolean.TRUE;
}
}
5、调用抽象方法
第一步,先把抽象类注入,这里以map的方式注入,key为beanName,值为具体的实现类。
@Resource
private Map<String, AbstractMsgCallBackHandler> abstractMsgCallBackHandlerMap;
第二步、通过类型获取beanName,从枚举中获取value
String beanName = MsgCallBackEnum.getBeanName(messageType);
第三步、通过beanName获取抽象类
AbstractMsgCallBackHandler abstractMsgCallBackHandler = abstractMsgCallBackHandlerMap.get(beanName);
第四步、调用抽象类抽象方法,会自动指向实现类
abstractMsgCallBackHandler.process(json);
整体的代码大概是这样的:
@Slf4j
@RestController
@RequestMapping("/callBack")
public class CallBackController {
@Resource
private WxAdminService wxAdminService;
@Resource
private Map<String, AbstractMsgCallBackHandler> abstractMsgCallBackHandlerMap;
/**
* 消息接收服务地址
*
* @param msg
* @return
*/
@TokenNeedless
@PostMapping("/getMsgCallBack")
public Result getMsgCallBack(@RequestBody String msg) {
JSONObject json = JSONObject.parseObject(msg);
//消息类型
Integer messageType = json.getInteger("messageType");
log.info("getMsgCallBack:{}", msg);
String beanName = MsgCallBackEnum.getBeanName(messageType);
AbstractMsgCallBackHandler abstractMsgCallBackHandler = abstractMsgCallBackHandlerMap.get(beanName);
if (abstractMsgCallBackHandler == null) {
return Result.ok();
}
Boolean process = abstractMsgCallBackHandler.process(json);
log.info("getMsgCallBack_process:{}", process);
return Result.ok();
}
}
这样以后有新的类型,直接写一个实现抽象类的类就可以了,代码藕和度下降很多。
四、总结
- 何时使用
一个系统有许多类,而区分它们的只是他们直接的行为时 - 方法
将这些算法封装成一个一个的类,任意的替换 - 优点
算法可以自由切换
避免使用多重条件判断(如果不用策略模式我们可能会使用多重条件语句,不利于维护)
扩展性良好,增加一个策略只需实现接口即可 - 缺点
策略类数量会增多,每个策略都是一个类,复用的可能性很小
所有的策略类都需要对外暴露 - 使用场景
多个类只有算法或行为上稍有不同的场景
算法需要自由切换的场景
需要屏蔽算法规则的场景
相关文章
- Android应用中MVP开发模式
- MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用
- MySQL高可用在网易的最佳应用与实践
- Apache Log4j爆“核弹级“漏洞,对众多java应用平台造成影响,已发现近万次攻击
- QT 应用部署到Android的终端步骤
- 移动支付技术架构及应用模式探讨
- js 的try catch应用
- 刘强东痛批京东中高层拿 PPT 欺骗自己;拼多多海外版成美国下载量最高应用;腾讯加入 RISC-V 基金会|极客头条
- 命令模式在MVC框架中的应用
- 解析S2B2C模式的典型特征,应用S2B2C商城助力医疗器械企业快速发展
- 微应用模式在集团企业移动信息化中的实践
- 《中国人工智能学会通讯》——12.2 大数据环境下序列模式挖掘及应用
- cube-ui按钮配合toast单例模式应用
- 项目设计之一-------------策略模式应用
- JAVA card 应用开发(二) 在项目添加APPLET
- ehcache 一二事 - ssm 中ehcashe的简单配置应用
- 云计算应用正在快速兴起
- Java反射机制在工厂模式中的应用
- Android应用中如何调用系统闹钟及日历
- 微服务的两种模式:应用中心和任务中心
- Enterprise Library深入解析与灵活应用(3):倘若将Unity、PIAB、Exception Handling引入MVP模式.. .. ..
- 白板类应用的模式交互设计方案
- 我的Android进阶之旅------>Android中查看应用签名信息