美文网首页
策略模式

策略模式

作者: 程序员小杰 | 来源:发表于2020-10-06 16:04 被阅读0次

假设现在要开发一个邮件服务,要对接所有的邮件服务提供厂商,那么代码可能是这样的:

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!这简直是灾难,让我们用策略模式让代码更加具备扩展性吧。

设计思想

image

Context: 对策略进行封装,对外暴露统一的方法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","假期余额不足");
    }
结果:
现在向网易邮箱发送邮件:假期余额不足

推荐:
https://www.jianshu.com/p/bd7ef2d145cb

相关文章

网友评论

      本文标题:策略模式

      本文链接:https://www.haomeiwen.com/subject/wpjtpktx.html