策略模式


背景

??之前接的一个需求,在创建店铺页面,根据用户的选择来判断到底是创建新系统店铺还是旧系统的店铺。一般情况下,都是根据前端传入的参数进行if else判断。但既然都是Senior Java Developer了,那就玩点花活吧,于是决定使用策略模型来实现。

实现

??策略模式,大白话来说,就是不同的场景下使用不同的策略来完成任务。在我这个场景中,需要根据前端传入的不同参数来实现不同的开店策略。先定义一个开店策略,具体的逻辑由实现类实现,如下:

          /**
           * @author Reece
           * @Description 策略接口
           */
          public interface CreateShopStrategy {


            /*
             * 创建店铺
             * @param reqVO
             * @return com.example.demos.model.ShopVO
             * @author Reece
             * @date 2022/4/10 20:14:02
             */
            ShopVO createShop(CreateShopReqVO reqVO);


            /*
             * 具体的策略类型
             * @param
             * @return java.lang.Integer
             * @author Reece
             */
            Integer getType();
          }

然后就是策略集合,到底有多少种策略,使用枚举就可以了。

          /**
           * @author Reece
           * @Description 策略集合
           */
          @Getter
          public enum StrategyType {

            OLD(1,"旧系统"),
            NEW(2,"新系统");


            private final Integer type;


            private final String desc;


            StrategyType(Integer type, String desc) {
              this.type = type;
              this.desc = desc;
            }
          }

??接下来就是具体的子类实现类了。

            /**
             * @author Reece
             * @Description 旧系统的开店逻辑
             */
            @Service
            public class OldCreateShopImpl extends CreateShopStrategy {



              @Override
              public ShopVO createShop(CreateShopReqVO reqVO) {
                return ShopVO.builder().shopName("OldCreateShopImpl").uid(reqVO.getUid()).id(new Random().nextLong()).build();
              }


              @Override
              public Integer getType() {
                return StrategyType.OLD.getType();
              }

            }


            /**
             * @author Reece
             * @Description 新系统的开店逻辑
             */
            @Service
            public class NewCreateShopImpl extends CreateShopStrategy {


              @Override
              protected ShopVO createShop(CreateShopReqVO reqVO) {
                return ShopVO.builder().shopName("NewCreateShopImpl").uid(reqVO.getUid()).id(new Random().nextLong()).build();
              }

              @Override
              protected Integer getType() {
                return StrategyType.NEW.getType();
              }

            }

好了,实现类都有了,策略模式的开发完成了。但是现在又有新的问题,前端传入了type,难道还使用if(type==?)来判断?策略模式没有之前,我用if else来判断。策略模式有了,我还是用if else来判断。那策略模式不就白写了么? 淡定,淡定,接下来就是工厂模式该出场的时候了。

所谓工厂模式即是在创建对象时对客户端屏蔽具体的创建逻辑,只通过接口来返回所需的具体对象。这里我们利用Spring容器的自动注入来方便快捷地实现工厂模式。

          /**
           * @author Reece
           * @Description
           */
          @Component
          public class CreateShopStrategyFactory implements ApplicationContextAware {


            // 缓存
            private static final Map STRATEGY_MAP = new ConcurrentHashMap<>();



            /**
             * 根据不同的type返回具体的策略
             *
             * @param type
             * @return com.example.demos.strategy.CreateShopStrategy
             * @author Reece
             * @date 2022/4/10 19:39:19
             */
            public CreateShopStrategy get(Integer type) {
              // 从缓存中获取具体的实现类
              return STRATEGY_MAP.get(type);
            }


            @Override
            public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

              // 获取容器中所有实现CreateShopStrategy的实现类
              Map strategyMap = applicationContext.getBeansOfType(CreateShopStrategy.class);

              // 设置进缓存中
              strategyMap.values().forEach(strategy -> STRATEGY_MAP.put(strategy.getType(), strategy));

            }
          }

验证

上面已经完成了策略模式,剩下就是验证策略模式是否成功。

            /**
             * @author Reece
             * @Description
             */
            @Service
            public class ShopServiceImpl implements ShopService {


              @Autowired
              private CreateShopStrategyFactory shopStrategyFactory;


              @Override
              public ShopVO createShop(CreateShopReqVO reqVO) {

                // 获取具体的实现策略
                CreateShopStrategy createShopStrategy = shopStrategyFactory.get(reqVO.getType());
                // 获取返回值
                return createShopStrategy.createShop(reqVO);
              }

            }



            /**
             * @author Reece
             * @Description
             */
            @Controller
            @RequestMapping("/shop")
            public class ShopController {


              @Autowired
              private ShopService shopService;



              @ResponseBody
              @PostMapping("/createShop")
              public ShopVO createShop(CreateShopReqVO reqVO) {
                return shopService.createShop(reqVO);
              }
            }

??启动SpringBoot应用,传入不同的参数调用接口。

??type为1时,如下所示:

image-20220410205705268

??type为2时,如下所示:

image-20220410205639454

??至此,策略模式已完成,详细的源码请点击demos查看