设计模式之策略模式

203 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情

简介

策略模式的简介是:

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

策略模式是我们业务开发中应用场景较多也比较好用的一种设计模式,使用策略模式可以将有效较少我们业务逻辑代码中的if/else,能有效解耦业务代码,而且符合开闭原则:需要增加策略的时候可以方便拓展,而不影响现存业务代码。

策略模式适合在一项流程或者业务中有多种实现方案,而这些方案之间又是互斥的关系,这里的方案即我们模式中的策略,我们就可以用一个容器来管理这一组策略,当业务逻辑运行到此需要调用某项策略时,通过此容器类(即环境类)查询到对应的策略进行调用即可,避免在业务代码中根据条件去做if/else调用策略。

故策略模式中涉及到的角色有3种:

  • 策略的抽象类:定义策略的抽象方法
  • 策略的实现类:用于实现各种解决方案
  • 环境类(即上文所述容器类):主要用于保存策略实现类列表

案例

我就那最近项目的伪代码来讲解策略模式的实现。背景是实现一个获取业务详情的接口,要根据不同的业务类型传入业务id去不同的服务查询详细数据。这就是一个典型的策略模式的场景,满足策略模式的基本条件:1、获取业务详情有不同的方案,到不同服务去查;2、各个业务类型是互斥的。那话不多说,直接上代码。

首先我们定义一个抽象的策略类:

public interface BusiStrategy {
    /**
     * 获取业务详情
     * @return
     */
    ResponseEntity doGetData(String bussNo) throws Exception;

}

分别定义几个业务的实现类。包含修改手机号码的业务、转账的业务

public class ModifyPhoneStrategy implements BusiStrategy {
    @Override
    public ResponseEntity doGetData(String bussNo) throws Exception {
        ModifyPhoneService modifyPhoneService = (ModifyPhoneService)SpringContextUtil.getBean("modifyPhoneService");
        return modifyPhoneService.getModifyInfo(bussNo);
    }
}
public class TransferStrategy implements BusiStrategy {
    @Override
    public ResponseEntity doGetData(String bussNo) throws Exception {
        TransferService transferService = (TransferService) SpringContextUtil.getBean("transferService");
        return transferService.getTransferInfo(bussNo);
    }

}

然后再定义一个环境类,用户保存要使用的策略,这里使用构造方法的方式注入想要使用的策略:

public class BusiContext {
    private BusiStrategy myStrategy;
    public BusiContext(BusiStrategy myStrategy){
        this.myStrategy = myStrategy;
    }
    public ResponseEntity getBusiDetail(String bussNo) throws Exception {
        return myStrategy.doGetData(bussNo);
    }
}

最后我们来根据情况调用策略:

public ResponseEntity getBusiDetail(String bussCode) throws Exception {
    //大额查询业务详情
    if (BussEnums.MOBILE_PHONE_MODIFY.getBussCode().equals(bussCode)) {
        busiStrategy = new ModifyPhoneStrategy();
    }else if(BussEnums.CASH_TRANSFER.getBussCode().equals(bussCode)) {
        busiStrategy = new TransferStrategy();
    }else {
        logger.error("查询不到对应的查询策略", JSON.toJSONString(responseEntity));
    }
    BusiContext strategy = new BusiContext(busiStrategy);
    return strategy.getBusiDetail(busiDetailRequest.getBussNo());
}

可能看完最后的调用方法有的同学会说了,这里还不是要写很多if/else。这里我要说的是不错这里确实是有这个问题,所以更好的方式是通过查询所有实现了BusiStrategy接口的获取所有的策略类保存在容器中,然后通过定义一个通过业务类型获取策略的方法即可。

总结

当然策略模式的确有很多优点,也比较好理解和使用。但是建议大家在策略类较多的情况下要考虑怎么去避免策略过多的问题,是不是可以考虑使用享元模式来共享策略实现中部分可以公用的部分,因为设计模式往往是结合起来一起使用才能扬长避短。