基于策略模式实现灵活可扩展的短信服务架构

基于策略模式实现灵活可扩展的短信服务架构

引言

在企业级应用开发中,短信服务是不可或缺的基础功能之一。随着业务发展,我们可能需要接入多个短信服务提供商(如阿里云、腾讯云、第三方短信网关等),并能够在不修改核心业务代码的情况下灵活切换。本文将介绍如何使用策略模式设计一个高扩展性的短信服务架构,并结合实际代码示例进行讲解。

策略模式简介

策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户端。

策略模式的三大角色

  1. 策略接口(Strategy Interface):定义所有支持的算法的公共接口
  2. 具体策略(Concrete Strategies):实现策略接口的具体算法类
  3. 上下文(Context):持有一个策略对象的引用,并将客户端请求委托给策略对象

短信服务架构设计

1. 策略接口设计

java 复制代码
@Service
public interface SmsComInterFace {
    public R sendSms(String phoneNumber, Map<String, Object> templateParams);
}

这里使用了Spring的@Service注解标记接口,虽然对接口使用@Service不是必须的,但在某些框架中可以辅助组件扫描。

2. 具体策略实现

以阿里云短信服务为例,实现具体的策略:

java 复制代码
package com.ruoyi.sms.config;

import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.sms.inter.SmsComInterFace;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class AliyunSmsUtil implements SmsComInterFace {
    @Value("${aliyun.sms.sms-access-key-id}")
    private String accessKeyId;

    @Value("${aliyun.sms.sms-access-key-secret}")
    private String accessKeySecret;

    @Value("${aliyun.sms.sms-sign-nam}")
    private String signName;

    @Value("${aliyun.sms.sms-template-code}")
    private String templateCode;

    @Value("${aliyun.sms.sms-endpoint}")
    private String endpoint;
    @Value("${aliyun.sms.region-id}")
    private String regionId;


    public  R sendSms(String phoneNumber, Map<String, Object> templateParams) {
        try {
            DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
            IAcsClient client = new DefaultAcsClient(profile);

            SendSmsRequest request = new SendSmsRequest();
            request.setPhoneNumbers(phoneNumber);
            request.setSignName(signName);
            request.setTemplateCode(templateCode);
            // 将HashMap转化为JSON字符串
            String templateParam = JSON.toJSONString(templateParams);
            request.setTemplateParam(templateParam);

            SendSmsResponse response = client.getAcsResponse(request);
            if(response.getCode() != null && response.getCode().equals("OK")){
                return R.ok();
            }
            return R.fail(response.getMessage());
        } catch (ClientException e) {
            e.printStackTrace();
            return null;
        }
    }

}

3. 策略工厂与上下文

策略工厂负责管理和提供具体的策略实现:

java 复制代码
package com.ruoyi.sms.handler;

import com.ruoyi.sms.config.AliyunSmsUtil;
import com.ruoyi.system.api.constants.SmsType;
import com.ruoyi.sms.inter.SmsComInterFace;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description:
 * @author: zh
 * @Create : 2025/4/30
 * @Project_name : RuoYi-Cloud
 * @Version :
 **/
@Component
@Slf4j
public class SmsTypeFactory {
    // 短信方式常量
    private static Map<String, SmsComInterFace> map = new ConcurrentHashMap<>();
    //上下文
    @Autowired
    private ApplicationContext applicationContext;
    
    @PostConstruct
    public void init()
        if(map.isEmpty()){
            //从上下文中找到所有实现了SmsComInterFace接口的类,并注册
            Map<String, SmsComInterFace> beansOfType = applicationContext.getBeansOfType(SmsComInterFace.class);
            beansOfType.forEach((k,v)->{
                map.put(k,v);
            });
        }
    }


    /**
     * 短信方式
     * @param type 传入短信方式
     * @return
     */
    public static SmsComInterFace getSms(String type) {
        SmsComInterFace sms = null;
        if(map.containsKey(type)){
            sms = map.get(type);
        }
        if (sms == null) {
            throw new NullPointerException("方式选择错误");
        }
        return sms;
    }
}

策略模式的应用

在实际业务中使用短信服务:

java 复制代码
@RestController
@RequestMapping("/sms")
public class SmsController {
    
    @GetMapping("/send/{phone}")
    public R sendSms(@RequestParam Map<String, Object> params, 
                    @PathVariable String phone,
                    @RequestParam String type) {
        try {
            SmsComInterFace sms = SmsTypeFactory.getSms(type);
            return sms.sendSms(phone, params);
        } catch (IllegalArgumentException e) {
            return R.fail(e.getMessage());
        }
    }
}

策略模式的扩展性

当需要新增短信服务提供商时,只需:

  1. 实现SmsComInterFace接口
  2. 在工厂类中注册新策略
  3. 无需修改现有代码

例如新增腾讯云短信服务:

java 复制代码
@Component
public class TencentSmsUtil implements SmsComInterFace {
    // 腾讯云实现...
}
//添加上Type
public class SmsType {
    public static final String TENCENT_SMS = "tencentSmsUtil";
}

策略模式的优势

  1. 开闭原则:无需修改现有代码即可扩展新策略

  2. 消除条件语句:避免大量的if-else或switch-case判断

  3. 易于测试:每个策略可以单独测试

  4. 运行时切换:可以根据配置动态切换策略

总结

通过策略模式设计短信服务架构,我们实现了:

  • 多种短信服务的统一接入
  • 业务代码与具体实现的解耦
  • 灵活的策略扩展能力
  • 便于维护和测试的代码结构

这种设计不仅适用于短信服务,也可以推广到支付网关、文件存储等需要支持多实现的场景。策略模式是保持软件扩展性和维护性的重要工具之一。

相关推荐
鹏程十八少2 小时前
7.Android 设计模式 享元模式 在商业项目中的落地
架构
老周聊大模型2 小时前
《ChatGLM/Llama调优实战:从指令微调到RLHF的工业级对齐方案》
人工智能·程序员·架构
weixin_437398213 小时前
转Go学习笔记
linux·服务器·开发语言·后端·架构·golang
搬砖的小码农_Sky4 小时前
XILINX Zynq-7000系列FPGA的架构
fpga开发·架构
zkmall6 小时前
企业电商解决方案哪家好?ZKmall模块商城全渠道支持 + 定制化服务更省心
大数据·运维·重构·架构·开源
美狐美颜sdk10 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
小雷FansUnion13 小时前
深入理解MCP架构:智能服务编排、上下文管理与动态路由实战
人工智能·架构·大模型·mcp
慌糖13 小时前
微服务介绍
微服务·云原生·架构
June bug14 小时前
【软考中级·软件评测师】下午题·面向对象测试之架构考点全析:分层、分布式、微内核与事件驱动
经验分享·分布式·职场和发展·架构·学习方法·测试·软考
森焱森17 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机