策略模式+简单工厂
以实际案例为主,第三方服务(例如微信、支付宝、支付核心等)回调我们服务的时候,它会带上一个字段代表本次回调的事件类型(假设字段名为: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(); } }
/** * @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); }
/** * @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; }
/** * @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("执行该事件对应的业务逻辑"); } }
经过使用了策略模式+简单工厂方案后,已经消除了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(); } }
StrategyService工厂服务以及impl服务实现(也就是具体的处理者)跟上面一样
如有问题还请留言,一起学习讨论共同进步