在之前的文章中,曾经给大家介绍过策略模式:【设计模式】策略模式,在该篇文章中,我们曾很清楚的说到,策略模式主要解决的问题是:在有多种算法相似的情况下,解决使用 if...else 所带来的复杂和难以维护。策略模式使我们的实现更加符合开闭原则:面向扩展开发,面向修改关闭。在后来的学习和工作的多次应用中,有了更加深刻的认识。再次总结此篇文章赘述下。
此篇文章,将以创建订单为例,创建不同类型的订单,不同类型的订单不同的处理逻辑
类图:
代码:
package strategyTest; import strategyTest.dto.BaseRequestDTO; /** * 类 名 称:CreateStrategy * 类 描 述:策略抽象类 * 创建时间:2023/2/20 3:46 下午 * 创 建 人:admin */ public abstract class AbstractOrderStrategy { public abstract Boolean isPracticable(BaseRequestDTO dto); // 业务执行总流程 public ResponseResult process(BaseRequestDTO dto) { ResponseResult paramsValidate = validateParams(dto); if (!paramsValidate.isSuccess()) { return paramsValidate; } ResponseResult ruleValidate = validateRules(dto); if (!ruleValidate.isSuccess()) { return ruleValidate; } ResponseResult processResult = doProcess(dto); if(processResult.isSuccess()){ postProcessAction(dto); } return processResult; } // 参数校验 protected abstract ResponseResult validateParams(BaseRequestDTO dto); // 业务规则校验 protected abstract ResponseResult validateRules(BaseRequestDTO dto); // 核心实现 protected abstract ResponseResult doProcess(BaseRequestDTO dto); // 后置处理(异步操作等) protected abstract void postProcessAction(BaseRequestDTO dto); }
2.具体策略(ConcreteStrategy)角色:实现封装了具体的算法或行为;
顺风车类型处理:
1. package strategyTest.impl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import strategyTest.AbstractOrderStrategy; import strategyTest.ResponseResult; import strategyTest.dto.BaseRequestDTO; import strategyTest.dto.SfcRequestDTO; /** * 类 名 称:SfcImpl * 类 描 述:TODO * 创建时间:2023/2/20 3:58 下午 * 创 建 人:admin */ @Service public class SfcImpl extends AbstractOrderStrategy { private Logger logger = LoggerFactory.getLogger(SfcImpl.class); @Override public Boolean isPracticable(BaseRequestDTO dto) { if(dto.getType() == 1){ return true; } return false; } @Override protected ResponseResult validateParams(BaseRequestDTO dto) { SfcRequestDTO sfcRequestDTO = (SfcRequestDTO) dto; if (sfcRequestDTO.getIsShare() == null || sfcRequestDTO.getIsShare() == 0) return ResponseResult.ERROR; logger.info("sfc validateParams success"); return ResponseResult.SUCCESS; } @Override protected ResponseResult validateRules(BaseRequestDTO dto) { // 无校验 return ResponseResult.SUCCESS; } @Override protected ResponseResult doProcess(BaseRequestDTO dto) { logger.info("sfc doProcess success"); return ResponseResult.SUCCESS; } @Override protected void postProcessAction(BaseRequestDTO dto) { logger.info("sfc 异步执行..."); } }
巴士订单处理:
package strategyTest.impl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import strategyTest.AbstractOrderStrategy; import strategyTest.ResponseResult; import strategyTest.dto.BaseRequestDTO; import strategyTest.dto.BusRequestDTO; /** * 类 名 称:BusImpl * 类 描 述:TODO * 创建时间:2023/2/20 3:58 下午 * 创 建 人:admin */ @Service public class BusImpl extends AbstractOrderStrategy { private Logger logger = LoggerFactory.getLogger(BusImpl.class); @Override public Boolean isPracticable(BaseRequestDTO dto) { if (dto.getType() == 2) { return true; } return false; } @Override protected ResponseResult validateParams(BaseRequestDTO dto) { BusRequestDTO busRequestDTO = (BusRequestDTO) dto; if (busRequestDTO.getRouteId() == null || busRequestDTO.getRouteId() == 0) return ResponseResult.ERROR; logger.info("bus validateParams success"); return ResponseResult.SUCCESS; } @Override protected ResponseResult validateRules(BaseRequestDTO dto) { BusRequestDTO busRequestDTO = (BusRequestDTO) dto; if (busRequestDTO.getSeats() != null && busRequestDTO.getSeats() > 30) return ResponseResult.ERROR; logger.info("bus validateRules success"); return ResponseResult.SUCCESS; } @Override protected ResponseResult doProcess(BaseRequestDTO dto) { logger.info("bus doProcess success"); return ResponseResult.SUCCESS; } @Override protected void postProcessAction(BaseRequestDTO dto) { logger.info("bus 异步执行..."); } }
3.上下文(Context)角色:持有抽象策略类的引用。(引用,执行策略)
package strategyTest; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; import strategyTest.dto.BaseRequestDTO; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * 类 名 称:StrategyContext * 类 描 述:策略执行上下文 * 创建时间:2023/2/20 3:47 下午 * 创 建 人:admin */ @Component public class StrategyContext{ // 策略管理类 @Autowired private List<AbstractOrderStrategy> strategies = new ArrayList<>(); // 获取策略类 public AbstractOrderStrategy getStrategy(BaseRequestDTO dto) { for (AbstractOrderStrategy strategy : strategies) { if (strategy.isPracticable(dto)) { return strategy; } } return null; } }
调用方client:
可以在一个controller,也可以写在多个controller
package strategyTest.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import strategyTest.AbstractOrderStrategy; import strategyTest.ResponseResult; import strategyTest.StrategyContext; import strategyTest.dto.BaseRequestDTO; import strategyTest.dto.BusRequestDTO; import strategyTest.dto.SfcRequestDTO; /** * 类 名 称:客户端请:可以充当controller或者业务调用上游 * 类 描 述:TODO * 创建时间:2023/2/20 3:58 下午 * 创 建 人:admin */ @RestController public class ClientTest { @Autowired private StrategyContext strategyContext; @RequestMapping("/createSfc") public ResponseResult createSfc(SfcRequestDTO sfcRequestDTO){ if(sfcRequestDTO == null){ return ResponseResult.ERROR; } return this.createOrder(sfcRequestDTO); } @RequestMapping("/createBus") public ResponseResult createBus(BusRequestDTO busRequestDTO){ if(busRequestDTO == null){ return ResponseResult.ERROR; } return this.createOrder(busRequestDTO); } private ResponseResult createOrder(BaseRequestDTO baseRequestDTO) { AbstractOrderStrategy strategy = strategyContext.getStrategy(baseRequestDTO); if(strategy == null){ return ResponseResult.ERROR; } return strategy.process(baseRequestDTO); } }
我们看下运行结果:
sfc运行结果:
bus运行结果:
是不是非常简洁明了!!!
我们看完代码,再结合类图看下,此时如果我们想新增一种类型的创建订单流程,比如创建一笔代驾订单,需要如何做? 我们只需要做两步:
1、新增一个代驾的实现类DjImpl,继承StrategyContext类;
2、在Controller中,新增一个方法(如果不同类型的订单有不在同一个controller,可将createOrder方法抽象到父类controller,此时新增一个子类controller继承父类和父类的方法即可);
其他地方无需改动。。。其他类型的创建订单流程完全无改动,无影响。下单流程解耦,测试范围极大的降低。
想想我们在项目中,相似的场景写过多少if else。每次添加新的实现,是否影响到原有功能。结合这篇文章,希望能对读者朋友有所帮助。
总结:
策略模式帮助我们把相似的算法抽象,使用上下文管理抽象类的具体实现,每次新增算法时,只需新增具体实现。使我们的代码轻松解耦,符合开闭原则,极大的缩小了影响范围。是成为一名优秀工程师的必修课!