zoukankan      html  css  js  c++  java
  • 策略模式+简单工厂

    以实际案例为主,第三方服务(例如微信、支付宝、支付核心等)回调我们服务的时候,它会带上一个字段代表本次回调的事件类型(假设字段名为:event)。

    事件event的类型有很多种,每一种事件所对应处理的逻辑也不一样,如果不用设计模式的话,就如同以下代码写if-else

    @RestController
    @RequestMapping(value = "/**/server/paycore")
    @Api(tags = "G04-PayCoreController",  value= "支付核心回调控制层")
    @Slf4j
    public class PayCoreController {
    
        @ApiOperation (value = "G0401-支付核心通知回调", notes = "支付核心通知回调")
        @PostMapping ("/callback")
        public void payCorePayResult(@RequestBody JSONObject eventJson, HttpServletRequest request, HttpServletResponse response) throws Exception{
    ·     //获取事件类型   String event
    = eventJson.getString("event").toUpperCase(); if (StringUtils.equals("event1",event)){ System.out.println("接收event1回调"); System.out.println("执行event1相关业务逻辑"); } else if (StringUtils.equals("event2",event)){ System.out.println("接收event2回调"); System.out.println("执行event2相关业务逻辑"); } else if (StringUtils.equals("event3",event)){ System.out.println("接收event3回调"); System.out.println("执行event3相关业务逻辑"); } // ......未来可能还有好多个else if } }

    在遇到if-else的分支业务逻辑比较复杂时,我们都习惯于将其抽出一个方法或者封装成一个对象去调用,这样整个if-else结构就不会显得太臃肿。就上面例子,当回执的类型越来越多时,分支else if 就会越来越多,每增加一个回执类型,就需要修改或添加if-else分支,违反了开闭原则(对扩展开放,对修改关闭)

    因此引入“策略模式+简单工厂”相结合。

    我们知道, 策略模式的目的是封装一系列的算法,它们具有共性,可以相互替换,也就是说让算法独立于使用它的客户端而独立变化,客户端仅仅依赖于策略接口 。在上述场景中,我们可以把if-else分支的业务逻辑抽取为各种策略,我们可以将这段逻辑抽取到工厂类中去,这就是策略模式+简单工厂,代码如下:

    @RestController
    @RequestMapping(value = "/**/server/paycore")
    @Api(tags = "G04-PayCoreController",  value= "支付核心回调控制层")
    @Slf4j
    public class PayCoreController {
    
        @ApiOperation (value = "G0401-支付核心通知回调", notes = "支付核心通知回调")
        @PostMapping ("/callback")
        public R payCorePayResult(@RequestBody JSONObject eventJson, HttpServletRequest request, HttpServletResponse response) throws Exception{
            // TODO: 2021/9/8 待优化
            String event = eventJson.getString("event").toUpperCase();
            PayCoreCallbackStrategyService payCoreCallbackStrategy = EventFactory.getPayCoreCallbackStrategy(event);
            if (payCoreCallbackStrategy != null){
                payCoreCallbackStrategy.event(eventJson,request,response);
            }else {
                return R.failed("不存在该event事件");
            }
            return R.success();
        }
    }
    controller层
    /**
     * @Description:事件工厂
     * @author: wph
     * @date: 2021/9/8
     */
    @Component
    @Slf4j
    public class EventFactory {
    
        private static Map<String, PayCoreCallbackStrategyService> callbackStrategyServiceMap;
    
        private EventFactory() throws Exception{
            callbackStrategyServiceMap = new HashMap<>();;
            //通过反射的方式,获取指定包下的所有PayCoreCallbackStrategyService实现类,然后防到callbackStrategyServiceMap里
            String path = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
                    .concat(ClassUtils.convertClassNameToResourcePath("com.caih.linkfin.gjfs.api.modules.callback.service.impl"))
                    .concat("/*.class");// /*.class表示当前包名下所有类,/**/*.class表示impl包名下的所有子包的类
            ResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = pathMatchingResourcePatternResolver.getResources(path);
            MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(pathMatchingResourcePatternResolver);
            for (Resource resource : resources){
                MetadataReader metadataReader = readerFactory.getMetadataReader(resource);
                //扫描到的类名
                String className = metadataReader.getClassMetadata().getClassName();
                Class<?> clazz = Class.forName(className);
                //获取@service注解
                Service serviceAnnotation = clazz.getAnnotation(Service.class);
                if (serviceAnnotation != null){
                    PayCoreCallbackStrategyService serviceImplBean = (PayCoreCallbackStrategyService)clazz.newInstance();
                    //如果该service没有设置value,则用类名当作key
                    if (StringUtils.isEmpty(serviceAnnotation.value())){
                        callbackStrategyServiceMap.put(clazz.getSimpleName(),serviceImplBean);
                    }else{
                        callbackStrategyServiceMap.put(serviceAnnotation.value(),serviceImplBean);
                    }
                }
            }
        }
    
        /**
         * @Description: 根据event事件名称获取对应的bean
         * @author: wph
         * @date: 2021/9/8
         * @param event
         */
        public static PayCoreCallbackStrategyService getPayCoreCallbackStrategy(String event){
            return callbackStrategyServiceMap.get(event);
        }
    EventFactory 策略工厂
    /**
     * @Description: 支付核心回调策略服务
     * @author: wph
     * @date: 2021/9/5
     */
    public interface PayCoreCallbackStrategyService {
        /**
         * @Description: 响应事件
         * @author: wph
         * @date: 2021/9/5
         * @param eventJson 响应体
         */
        void event(JSONObject eventJson, HttpServletRequest request, HttpServletResponse response) throws Exception;
    }
    StrategyService工厂服务
    /**
     * @Description:工资单结果事件处理
     * @author: wph
     * @date: 2021/9/5
     */
    @Service("PAYRESULT")
    @Slf4j
    public class PayResult implements PayCoreCallbackStrategyService {
    
        /**
         * @Description: 响应事件
         * @author: wph
         * @date: 2021/9/5
         * @param eventJson 响应体
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void event(JSONObject eventJson, HttpServletRequest request, HttpServletResponse response){
            System.out.println("执行该事件对应的业务逻辑");
        }
    }
    impl服务实现(也就是具体的处理者)

    经过使用了策略模式+简单工厂方案后,已经消除了if-else的结构,每当新来了一种回执,只需要添加新的处理业务处理者即可,符合开闭原则

    说一下另一种方法比较简单,不需要编写EventFactory 策略工厂:

    @RestController
    @RequestMapping(value = "/**/server/paycore")
    @Api(tags = "G04-PayCoreController",  value= "支付核心回调控制层")
    @Slf4j
    public class PayCoreController {
    
        @ApiOperation (value = "G0401-支付核心通知回调", notes = "支付核心通知回调")
        @PostMapping ("/callback")
        public R payCorePayResult(@RequestBody JSONObject eventJson, HttpServletRequest request, HttpServletResponse response) throws Exception{
            String event = eventJson.getString("event").toUpperCase();
            //主要区别在这里
            PayCoreCallbackStrategyService payCoreCallbackStrategy = (PayCoreCallbackStrategyService) SpringContextUtils.getBean(event);
            if (payCoreCallbackStrategy != null){
                payCoreCallbackStrategy.event(eventJson,request,response);
            }else {
                return R.failed("不存在该event事件");
            }
            return R.success();
        }
    }
    controller层

    StrategyService工厂服务以及impl服务实现(也就是具体的处理者)跟上面一样

    如有问题还请留言,一起学习讨论共同进步

  • 相关阅读:
    对百度搜索法的分析评价
    第二阶段第十次spring会议
    课下作业——典型用户和用处场景
    第二阶段第九次spring会议
    第二阶段第八次spring会议
    第二阶段第七次spring会议
    第二阶段第六次spring会议
    第二阶段第五次spring会议
    第二阶段第四次spring会议
    第二阶段第三次spring会议
  • 原文地址:https://www.cnblogs.com/w-wu/p/15481737.html
Copyright © 2011-2022 走看看