关于这三种设计模式是什么这里就不再赘述,本篇文章主要讲的是应用,不理解概念的可以先看一下我的其他关于讲解设计模式的文章,接下来直接进入主题。
书接上文讲的策略+简单工厂模式,本次我们又引入了模板方法,将一些公用的方法定义在抽象类的方法中,不同子类各自实现各自的逻辑。
我们这次还是根据不同的渠道类型进行通知客户(渠道类型有短信sms、邮件email、钉钉dingTalk)
首先就是要有策略接口,接口里面要有一个方法就是通知的方法
java
public interface PushChannelStrategy{
SendResult send(MessagePushParam param,BaseMsg baseMsg);
}
然后是抽象类,抽象类中定义发送的通用流程,各自具体发送流程下沉到各自实现类
java
@Component
public abstract class AbstractPushChannelStrategy implements PushChannelStrategy{
@Override
public SendResult send(MessagePushParam parma,BaseMsg baseMsg){
// 获取目标地址,各自实现类来获取receiveAddress
ReceiverResult receiverResult =getReceiverAddress(param);
// 拿到通知的地址,即手机号、邮箱、钉钉id
String receiverAddress=receiverResult.getReceiverAddress();
// 非空校验
if(StringUtils.isBlank(receiverAddress)){
return new SendResult(MessageStatusEnum.SEND_ADDRESS_NOT_EXIST,param.getReceiverId(),receiverAddress);
}
// 开始发送(短信、邮件、钉钉),各自实现发送逻辑
return send(param,receiverAddress,baseMsg);
}
//获取目标地址
public abstract ReceiverResult getReceiverAddress(MessagePushParam param);
// 具体发送逻辑
public abstract SendResult send(MessagePushParam param,String targetId,BaseMsg BaseMsg);
然后三个子类短信、邮件、钉钉
java
@Slf4j
@Component
public class SmsPushChannelStrategy extends AbstractPushChannelStrategy{
@Autowired
private NoticeClient noticeClient;
@Autowired
private CustomerGateway customerGateway;
@Override
public SendResult send(MessagePushParam param,String targetId,BaseMsg baseMsg){
//1、send sms
if(baseMsg instanceof Sms){
Sms smsMsg=(Sms)baseMsg;
NoticeResult noticeResult=noticeClient.sendSms(xxxx);
SendResult sendResult=new SendResult();
sendResult.setMessageStatus(MessageStatusEnum.SUCCESS);
return sendResult;
}
throw new MessagePushException("渠道不支持该类型消息");
}
// 短信通知获取需要通知的手机号
@Override
public ReceiverResult getReceiverAddress(MessagePushParam param){
if(param==null){
return ReceiverResult.builder().status(MessageStatusEnum.SMS_QUERY_PARAM_NULL).build();
}
return customerGateway.getSmsResultByCustId(param.getCustomerId());
}
}
邮件:
java
@Slf4j
@Component
public class EmailPushChannelStrategy extends AbstractPushChannelStrategy{
@Autowired
private NoticeClient noticeClient;
@Autowired
private CustomerGateway customerGateway;
@Override
public SendResult send(MessagePushParam param,String targetId,BaseMsg baseMsg){
//1、send email
if(baseMsg instanceof Email){
Email emailMsg=(Email)baseMsg;
NoticeResult noticeResult=noticeClient.sendEmail(xxxx);
sendResult.setMessageStatus(MessageStatusEnum.SUCCESS);
return sendResult;
}
throw new MessagePushException(xxx);
}
@Override
public ReceiverResult getReceiverAddress(MessagePushParam param){
if(param==null){
return ReceiverResult.builder().status(xxx).build();
}
return customerGateway.getEmailResultByCustId(param.getCustomerId());
}
}
钉钉:
java
@Slf4j
@Component
public class DingTalkPushChannelStrategy extends AbstractPushChannelStrategy{
@Autowired
private DingTalkClient dingTalkClient;
@Autowired
private SalesGateway salesGateway;
@Override
public SendResult send(MessagePushParam param,BaseMsg baseMsg){
//1、send ding talk
SendResult sendResult=dingTalkClient.send(xxx);
sendResult.setReceiverId(param.getSalesId());
// 其他结果参数组装
return sendResult;
}
// 根据销售id获取钉钉id
@Override
public ReceiverResult getReceiverAddress(MessagePushParam param){
DingTalkResult dingTalkResult=salesGateway.getDingTalkResultBySalesId(param.getSalesId());
if(dingTalkResult==null){
return ReceiverResult.builder().status(xxx).receiverAddress(null).build();
}
return ReceiverResult.builder().status(MessageStatusEnum.SUCCESS).receiverAddress(dingTalkResult.getDingTalkId()).build();
}
}
然后通过策略工厂来获取具体的策略类:(由于只有三个策略类,所以通过注入的方式对channel进行判断)
java
@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("不支持的类型");
}
}
}
当然策略工厂针对策略实现类比较少的情况还可以这样写:
java
@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);
}
}
枚举类:
java
@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;
}
}
在使用的时候通过策略工厂里面的方法获取具体的策略类:
java
@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);
}
}
到此就结束了,是不是比较简单,该案例为实际项目中用到的实际案例,并且这三种设计模式也是比较简单和比较常用的设计模式,欢迎各位指出不足之处以及共同成长与学习。