本文介绍项目中常用的策略模式+工厂模式的案例,该案例是针对策略类比较少的情况;下一篇会讲解策略类比较多的案例,下面直接开始:
案例1:项目中对系统中的客户和销售进行事件通知(短信、邮件、钉钉)
首先要有通知的策略接口,接口里面要有一个方法就是通知的方法
public interface PushChannelStrategy{
// 通知方法
SendResult send(MessagePushParam param,BaseMsg baseMsg);
}
有了接口那必然有实现类,三个实现类短信、邮件、钉钉
短信:
@Slf4j
@Component
public class SmsPushChannelStrategy implements PushChannelStrategy{
@Autowired
private NoticeClient noticeClient;
@Override
public SendResult send(MessagePushParam param,BaseMsg baseMsg){
//1、before send check
//2、send sms
NoticeResult noticeResult=noticeClient.sendSms(xxxx);
sendResult.setMessageStatus(MessageStatusEnum.SUCCESS);
return sendResult;
}
}
邮件:
@Slf4j
@Component
public class EmailPushChannelStrategy implements PushChannelStrategy{
@Autowired
private NoticeClient noticeClient;
@Override
public SendResult send(MessagePushParam param,BaseMsg baseMsg){
//1、before send check
//2、send email
Email emailMsg=(Email)baseMsg;
NoticeResult noticeResult=noticeClient.sendEmail(xxxx);
sendResult.setMessageStatus(MessageStatusEnum.SUCCESS);
return sendResult;
}
}
钉钉:
@Slf4j
@Component
public class DingTalkPushChannelStrategy implements PushChannelStrategy{
@Autowired
private DingTalkClient dingTalkClient;
@Override
public SendResult send(MessagePushParam param,BaseMsg baseMsg){
//1、before send check
//2、send ding talk
SendResult sendResult=dingTalkClient.send(xxx);
// 其他结果参数组装
return sendResult;
}
}
然后通过策略工厂来获取具体的策略类:(由于只有三个策略类,所以通过注入的方式对channel进行判断)
@Component
public class PushChannelStrategyFactory{
@Autowired
private DingTalkPushChannelStrategy dingTalkPushChannelStrategy;
@Autowired
private SmsPushChannelStrategy smsPushChannelStrategy;
@Autowired
private EmailPushChannelStrategy emailPushChannelStrategy;
public PushChannelStrategy getStrategy(PushChannel pushChannel){
switch(pushChannel){
case DING_TALK:
return dingTalkPushChannelStrategy;
case SMS:
return smsPushChannelStrategy;
case EMAIL:
return emailPushChannelStrategy;
default:
throw new RuntimeException("不支持的类型");
}
}
}
当然策略工厂针对策略实现类比较少的情况还可以这样写:
@Component
public class PushChannelStrategyFactory2{
@Autowired
private DingTalkPushChannelStrategy dingTalkPushChannelStrategy;
@Autowired
private SmsPushChannelStrategy smsPushChannelStrategy;
@Autowired
private EmailPushChannelStrategy emailPushChannelStrategy;
private static final Map<PushChannel,PushChannelStrategy> pushChannelBuilderMap=new HashMap<>();
@PostConstruct
public void init(){
pushChannelBuilderMap.put(PushChannel.SMS,smsPushChannelStrategy);
pushChannelBuilderMap.put(PushChannel.Email,emailPushChannelStrategy);
pushChannelBuilderMap.put(PushChannel.DING_TALK,dingTalkPushChannelStrategy);
}
Public PushChannelStrategy getStrategy(PushChannel PushChannel){
if(PushChannel==null){
return null;
}
return pushChannelBuilderMap.get(PushChannel);
}
}
用到的枚举类:
@Getter
public enum PushChannel{
SMS("sms","短信"),
EMAIL("email","邮件"),
DING_TALK("dingTalk","钉钉");
private final String value;
PushChannel(String value,String desc){
this.value=value;
}
public static PushChannel getPushChannel(String pushChannel){
if(pushChannel==null){
return null;
}
for(PushChannel channel:PushChannel.values()){
if(pushChannel.equals(channel.getValue())){
return channel;
}
}
return null;
}
}
在使用的时候通过策略工厂里面的方法获取具体的策略类:
@Slf4j
@Service
public class MessagePushService{
@Autowired
private PushChannelStrategyFactory pushChannelStrategyFactory;
@Autowired
private MessageRecordRepository messageRecordRepository;
public ResultDTO<Boolean> pushSync(MessagePushCommand command){
MessagePushParam messagePushParam =MessagePushAssembler.convert(command);
//1,业务逻辑处理
//2、根据渠道进行触达
PushChannel pushChannel=messagePushParam.getChannel();
if(pushChannel==null){
throw new MessagePushException(xxx);
}
//3、获取具体的策略类
PushChannelStrategy pushChannelStrategy=pushChannelStrategyFactory.getStrategy(pushChannel);
SendResult sendResult=PushChannelStrategy.send(messagePushParam,xxx);
//4,记录落库
return ResultDTO.getSuccessResult(true);
}
}
到此该版本的策略模式+工厂模式就结束了,欢迎点评和指出不足之处。