假设现在要开发一个邮件服务,要对接所有的邮件服务提供厂商,那么代码可能是这样的:
public class MailHandle {
public void send(String providerName, String msg) {
// 如果要发到 qq邮箱
if ("qq".equals(providerName)) {
sendMsgToQQ(msg);
}
// 如果要发到网易邮箱
else if ("ntes".equals(providerName)) {
sendMsgToNtes(msg);
}
// 如果要发到阿里云邮箱
else if ("alibaba".equals(providerName)) {
sendMsgToAlibaba(msg);
}
}
}
Oh,My God!这简直是灾难,让我们用策略模式让代码更加具备扩展性吧。
设计思想
imageContext: 对策略进行封装,对外暴露统一的方法send()。
Strategy: 策略接口,定义抽象方法。
implStrategy: 图中的QQ,NTES,Alibaba都是Strategy的实现类。实现具体的业务方法。
策略模式 + 工厂模式
- MailStrategyService
public interface MailStrategyService {
/**
* 发送邮件
*
* @param message
*/
public void send(String message);
}
- NASDAQMailStrategyServiceImpl
public class NASDAQMailStrategyServiceImpl implements MailStrategyService{
@Override
public void send(String message) {
System.out.println("现在向网易邮箱发送邮件:" + message);
}
}
- QQMailStrategyServiceImpl
public class QQMailStrategyServiceImpl implements MailStrategyService {
@Override
public void send(String message) {
System.out.println("向QQ邮箱发送邮件:" + message);
}
}
- MailStrategyContext
public class MailStrategyContext {
private static MailStrategyContext factory = new MailStrategyContext();
private MailStrategyContext(){}
private static Map<String, MailStrategyService> strategyMap = new ConcurrentHashMap<>();
static {
strategyMap.put("ntes",new NASDAQMailStrategyServiceImpl());
strategyMap.put("qq",new QQMailStrategyServiceImpl());
}
public MailStrategyService creator(String pType,String message){
if (strategyMap.containsKey(pType)) {
MailStrategyService mailStrategyService = strategyMap.get(pType);
//发送邮件信息
mailStrategyService.send(message);
}
// 根据业务需求,确定默认返回的类型
return null;
}
public static MailStrategyContext getInstance(){
return factory;
}
}
测试
public static void main(String[] args) {
MailStrategyContext instance = MailStrategyContext.getInstance();
instance.creator("qq","你好,你的假期余额不足");
}
结果:
向QQ邮箱发送邮件:你好,你的假期余额不足
上面的策略模式还是有问题存在。每当我们接入一家邮件服务提供厂商的时候都要在MailStrategyContext类中的静态代码块中加入一个put。这就违反了设计模式的开闭原则。
Spirng + 策略模式
增加一个枚举统一管理提供厂商
- ProviderEnum
public enum ProviderEnum {
QQ("qq","QQ邮件服务提供厂商"),
NTES("ntes","网易邮件服务提供厂商");
private String key;
private String desc;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
ProviderEnum(String key, String desc) {
this.key = key;
this.desc = desc;
}
}
- MailStrategyService
MailStrategyService新增getServiceProviderName方法
public interface MailStrategyService {
/**
* 服务提供商名称
*
* @return
*/
public String getServiceProviderName();
/**
* 发送邮件
*
* @param message
*/
public void send(String message);
}
- NASDAQMailStrategyServiceImpl
NASDAQMailStrategyServiceImpl将该类交给Spirng管理,加上@Service注解并重写getServiceProviderName方法并指定厂商key
@Service
public class NASDAQMailStrategyServiceImpl implements MailStrategyService{
@Override
public String getServiceProviderName() {
return ProviderEnum.NTES.getKey();
}
@Override
public void send(String message) {
System.out.println("现在向网易邮箱发送邮件:" + message);
}
}
- QQMailStrategyServiceImpl
QQMailStrategyServiceImpl将该类交给Spirng管理,加上@Service注解并重写getServiceProviderName方法并指定厂商key
@Service
public class QQMailStrategyServiceImpl implements MailStrategyService {
@Override
public String getServiceProviderName() {
return ProviderEnum.QQ.getKey();
}
@Override
public void send(String message) {
System.out.println("向QQ邮箱发送邮件:" + message);
}
}
- MailStrategyContext
@Component
public class MailStrategyContext {
/**
* 策略
* KEY为业务编码
* VALUE为具体实现类
*/
private final ConcurrentHashMap<String, MailStrategyService> strategy = new ConcurrentHashMap<>();
/**
* 注入所有实现 MailStrategyService 接口的类
* 这里使用的是构造注入的方式将Bean注入进来
*
* @param mailServiceList
*/
public MailStrategyContext(List<MailStrategyService> mailServiceList) {
for (MailStrategyService mailStrategyService : mailServiceList) {
strategy.put(mailStrategyService.getServiceProviderName(), mailStrategyService);
}
}
/**
* 发送邮件
*
* @param strategyName 策略名称
* @param message 发送邮件信息
*/
public void send(String strategyName, String message) {
MailStrategyService mailStrategyService = strategy.get(strategyName);
mailStrategyService.send(message);
}
}
- 测试
@Autowired
MailStrategyContext mailStrategyContext;
@Test
void test1(){
mailStrategyContext.send("ntes","假期余额不足");
}
结果:
现在向网易邮箱发送邮件:假期余额不足
网友评论