一、整体设计思路
为了实现在短信服务提供商变更时,不修改现有代码就能无缝切换到新服务实现,可采用策略模式结合依赖注入以及配置中心化管理的方式来设计软件系统。
二、 具体实现步骤
1. 定义统一接口(以短信服务为例,接口命名为 SmsService
)
创建一个抽象的接口,用于定义该类服务的统一行为规范,所有具体服务提供商的实现类都需要遵循这个接口所定义的方法。例如:
public interface SmsService {
Response sendSms(Request request);
}
这里定义了 sendSms
方法,意味着不同短信服务提供商的具体实现类都要实现该方法来完成发送短信的操作,从外部调用角度来看,调用这个接口的 sendSms
方法就能获取相应的短信发送服务结果,无需关心具体是由哪个服务商来提供服务。
2. 实现具体服务提供商
针对不同的短信服务提供商,分别实现上述定义的 SmsService
接口,并在各自的实现类中封装对应服务商特有的业务逻辑。比如:
// 阿里云短信服务实现
@Service("aliyunSmsService")
public class AliyunSmsServiceImpl implements SmsService {
public AliyunSmsServiceImpl(
@Value("${sms.aliyun.accessKey}") String accessKey,
@Value("${sms.aliyun.secretKey}") String secretKey
) {
/* 初始化相关参数 */ }
@Override
public Response sendSms(Request request) {
// 此处编写调用阿里云短信 API 的具体逻辑
}
}
// 腾讯云短信服务实现
@Service("tencentSmsService")
public class TencentSmsServiceImpl implements SmsService {
public TencentSmsServiceImpl(
@Value("${sms.tencent.appId}") String appId,
@Value("${sms.tencent.secretKey}") String secretKey
) {
/* 初始化相关参数 */ }
@Override
public Response sendSms(Request request) {
// 编写调用腾讯云短信 API 的具体逻辑
}
}
3. 配置文件管理(以 application.yml
为例)
在配置文件中指定当前使用的短信服务提供商,同时配置各个提供商所需的相关参数,方便后续根据配置来获取和使用对应的服务。示例配置如下:
sms:
provider: aliyun # 可选值如: aliyun, tencent 等,代表不同的短信服务提供商
aliyun:
accessKey: your-aliyun-key
secretKey: your-aliyun-secret
tencent:
appId: your-tencent-app-id
secretKey: your-tencent-secret
4. 动态选择服务实现(配置类)
创建一个 Spring 配置类,用于根据配置文件中指定的短信服务提供商名称,从 Spring 容器中获取对应的具体服务实现类实例,并将其作为一个 Bean
提供给其他需要使用短信服务的地方。代码如下:
@Configuration
public class SmsServiceConfig {
@Bean
public SmsService smsService(
@Value("${sms.provider}") String provider,
Map<String, SmsService> smsServiceMap
) {
return smsServiceMap.get(provider + "SmsService");
}
}
这里的 smsService
方法被标注为 @Bean
,意味着该方法返回值会作为 Bean
被添加到 Spring 容器中供其他组件依赖注入使用。在方法参数中:
@Value("${sms.provider}") String provider
用于从配置文件中获取当前指定的短信服务提供商名称(如"aliyun"
或"tencent"
等)。Map<String, SmsService> smsServiceMap
是 Spring 容器自动管理的一个Map
结构,它的键(String
)是各个实现了SmsService
接口的Bean
名称(像"aliyunSmsService"
、"tencentSmsService"
等,由@Service
注解指定名称时确定),值(SmsService
)就是对应的实现了SmsService
接口的具体短信服务Bean
实例。Spring 容器在初始化SmsServiceConfig
类并处理smsService
这个@Bean
方法时,会自动查找类型为Map<String, SmsService>
的Bean
(也就是收集了所有实现Sms