java设计模式之:策略模式+简单工厂模式+模板方法模式项目案例实战

关于这三种设计模式是什么这里就不再赘述,本篇文章主要讲的是应用,不理解概念的可以先看一下我的其他关于讲解设计模式的文章,接下来直接进入主题。

书接上文讲的策略+简单工厂模式,本次我们又引入了模板方法,将一些公用的方法定义在抽象类的方法中,不同子类各自实现各自的逻辑。

我们这次还是根据不同的渠道类型进行通知客户(渠道类型有短信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);
    }
 }

到此就结束了,是不是比较简单,该案例为实际项目中用到的实际案例,并且这三种设计模式也是比较简单和比较常用的设计模式,欢迎各位指出不足之处以及共同成长与学习。

相关推荐
考虑考虑1 小时前
Jpa使用union all
java·spring boot·后端
用户3721574261351 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊2 小时前
Java学习第22天 - 云原生与容器化
java
渣哥4 小时前
原来 Java 里线程安全集合有这么多种
java
间彧4 小时前
Spring Boot集成Spring Security完整指南
java
间彧5 小时前
Spring Secutiy基本原理及工作流程
java
数据智能老司机5 小时前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
Java水解6 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
数据智能老司机7 小时前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
洛小豆8 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试