赞
踩
官话:策略模式(Strategy Pattern): 定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化。
简单理解就是,针对不同的场景,使用不同的策略进行处理;
场景:最近太热了,想要降降温,有什么办法呢
首先,定义一个降温策略的接口
public interface CoolingStrategy {
/**
* 处理方式
*/
void handle();
}
定义3种降温策略;实现策略接口
public class IceCoolingStrategy implements CoolingStrategy {
@Override
public void handle() {
System.out.println("使用冰块降温");
}
}
public class FanCoolingStrategy implements CoolingStrategy {
@Override
public void handle() {
System.out.println("使用风扇降温");
}
}
public class AirConditionerCoolingStrategy implements CoolingStrategy {
@Override
public void handle() {
System.out.println("使用空调降温");
}
}
定义一个降温策略的上下文
public class CoolingStrategyContext {
private final CoolingStrategy strategy;
public CoolingStrategyContext(CoolingStrategy strategy) {
this.strategy = strategy;
}
public void coolingHandle() {
strategy.handle();
}
}
测试
public class Main {
public static void main(String[] args) {
CoolingStrategyContext context = new CoolingStrategyContext(new FanCoolingStrategy());
context.coolingHandle();
context = new CoolingStrategyContext(new AirConditionerCoolingStrategy());
context.coolingHandle();
context = new CoolingStrategyContext(new IceCoolingStrategy());
context.coolingHandle();
}
}
运行结果:
使用风扇降温
使用空调降温
使用冰块降温
以上就是一个策略模式的简单实现
以我自己在工作中遇到的场景为例,《企业微信会话存档》功能,获取各种格式的消息内容,进行解析并保存数据。这里只针对消息处理的功能模块,其他关于《企业微信会话存档》的功能,请参见会话存档-如何高性能存储海量聊天记录、企业微信会话存档-文件下载
企业微信会话聊天会产生如下多种消息,在SpringBoot项目中应该如何使用策略模式来完成消息的解析呢?
获取会话内容 - API 看API内容,数据都是json格式。思考应该如何处理:
首先,既然要解析各种数据,而每种数据格式结构都不一样,那么就需要先根据每种消息格式定义各自的对象,然后根据不同的需求,将json格式处理成pojo对象;
根据场景,需要定义两个策略接口,一个是针对普通的文本格式消息的策略,另一个则是需要处理文件格式消息的策略;
定义策略处理上下文操作类,用于使用策略
每种消息,都会有一些相同的数据,比如发送人、接收人、消息类型等;根据消息类型的不同,使用 key-value 的方式,让调用者确定应该使用哪个策略来处理数据
因为格式太多,这里只使用两个格式作为例子
两个策略接口
public interface Strategy {
/**
* 处理会话存档的内容
*
* @param content json格式的消息内容
* @return 结果
*/
<T> T handleContent(String content);
}
public interface MediaStrategy {
/**
* 处理会话存档媒体内容
*
* @param msgData 消息内容
*/
<T> void handleMedia(T msgData);
}
策略的具体实现(伪代码)
@Component("link")
public class LinkStrategy implements Strategy {
@Override
public LinkPO handleContent(String content) {
// JSON 转换为具体对象
LinkWrapDTO linkWrapDTO = JacksonUtils.json2Obj(content, LinkWrapDTO.class);
// 将对象处理成业务需要的格式
return Convert.convert(LinkPO.class, linkWrapDTO);
}
}
@Component("image") public class ImageStrategy implements Strategy, MediaStrategy { @Autowired private IMsgFileService msgFileService; @Override public ImagePO handleContent(String content) { // JSON 转换为具体对象 ImageWrapDTO imageWrapDTO = JacksonUtils.json2Obj(content, ImageWrapDTO.class); // 将对象处理成业务需要的格式 return Convert.convert(ImagePO.class,imageWrapDTO); } @Override public <T> void handleMedia(T msgData) { // 将数据格式转换为具体实现的数据格式 ImagePO imagePo = Convert.convert(ImagePO.class, msgData); // 调用文件服务,进一步处理文件 msgFileService.newFileTask(imagePo.getImage().getSdkfileid(), imagePo.getMsgid() + ".jpg", imagePo.getMsgid(), imagePo.getSeq(), imagePo.getImage().getFilesize(), imagePo.getImage().getMd5sum(), MessageEnum.IMAGE); } }
策略上下文
@Component public class StrategyContext { @Resource Map<String, Strategy> strategys = new ConcurrentHashMap<>(); @Resource Map<String, MediaStrategy> mediaStrategys = new ConcurrentHashMap<>(); public Strategy getStrategy(String component) { return strategys.get(component); } public MediaStrategy getMediaStrategy(String component) { return mediaStrategys.get(component); } }
调用者(伪代码)
public class MsgService { @Resource private StrategyContext strategyContext; public void handlerMessage() { // 请求api获取消息的json json = api(); // 转为通用格式对象 basePo = JsonUtils.json2Obj(json, BasePO.class); // 选取不同的策略 Strategy strategy = strategyContext.getStrategy(basePo.getMsgType()); // 进行处理 strategy.handleContent(json); // 关于文件类消息的处理 MediaStrategy mediaStrategy = strategyContext.getMediaStrategy(basePo.getMsgtype()); if (null != mediaStrategy) { mediaStrategy.handleMedia(basePo); } } }
以上就是策略模式的一种实现方式;
从以上的例子很明显的可以看出,策略模式的灵活性;如果此时企业微信提供了一种新的消息格式,那么根本无需修改之前的代码,只需要再写一个新的类,实现消息处理策略的接口,重写处理方法即可;
了解策略模式的优点和缺点,再根据业务场景来判断是否需要使用策略模式
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。