前言: 之前写过一个工作中常见升级模式-策略模式 的文章,里面讲了具体是怎样使用策略模式去抽象现实中的业务代码,今天来拿出实际代码来写个demo,这里做个整理来加深自己对策略模式的理解。 一、业务流程 取消订单会有多种情况,比如:取消即时订单、取消预约订单、取消拼车订单 一般业务代码中我们会根据取消类型来进行不同的逻辑处理,代码中无外乎多了很多if else的业务逻辑,且代码耦合度很高。 那么有没有一种优雅的处理方式呢? 当然有了,现在就来说下我们系统中是如何处理这种问题的( 具体业务需求可以参考我上一篇文章:https://www.cnblogs.com/wang-meng/p/11457544.html) 二、流程图 上面已经说了业务流程,当然有流程图才是最直观的,这里我们可以直接参见下图: 这里我们可以使用Spring 获取到所有 AbstractOrderStrategy 实现类中@OrderTypeAnnotation注解的类,然后比较orderType即可。下面就看具体代码吧; 三、代码实现及解析 1、自定义订单类型枚举:OrderTypeAnnotation 复制代码 1 @Target({ElementType.TYPE}) 2 @Retention(RetentionPolicy.RUNTIME) 3 public @interface OrderTypeAnnotation { 4 OrderTypeEnum orderType(); 5 } 复制代码 这里 ElementType.TYPE表示用于类上,RetentionPolicy.RUNTIME 表示运行时解析的。更多的含义大家可以看注解的相关知识。 2、构建OrderType枚举:OrderTypeEnum 复制代码 1 public enum OrderTypeEnum { 2 INSTANT(1, "即时订单"), 3 BOOKING(2, "预约订单"), 4 CARPOOL(3, "拼车订单"); 5 6 7 private int code; 8 private String desc; 9 10 11 OrderTypeEnum(int code, String desc) { 12 this.code = code; 13 this.desc = desc; 14 } 15 16 17 public int getCode() { 18 return code; 19 } 20 21 22 public String getDesc() { 23 return desc; 24 } 25 26 27 public static OrderTypeEnum getByCode(int code) { 28 for (OrderTypeEnum orderTypeEnum : values()) { 29 if (orderTypeEnum.getCode() == code) { 30 return orderTypeEnum; 31 } 32 } 33 return null; 34 } 35 } 复制代码 这里会显示该取消订单的类型,如过往代码中所有if 中的条件判断,这里用枚举进行归纳。 3、构建抽象策略及策略实现类 策略抽象类:AbstractOrderStrategy 复制代码 1 public abstract class AbstractOrderStrategy { 2 3 /** 4 * 策略抽象方法 5 * @param orderDTO 6 */ 7 abstract public void process(OrderDTO orderDTO); 8 } 复制代码 为了容易理解,这里只有一个业务实现类,继承该抽象类的策略类都会实现具体的业务。 预约单处理策略类:BookingOrderStrategy 复制代码 1 @Service 2 @OrderTypeAnnotation(orderType = OrderTypeEnum.BOOKING) 3 public class BookingOrderStrategy extends AbstractOrderStrategy { 4 5 @Override 6 public void process(OrderDTO orderDTO) { 7 System.out.println("取消预约订单"); 8 } 9 } 复制代码 这里重点关注orderType,代码区分具体的执行策略 都是通过这个type去进行处理的。 即时单处理策略类:InstantOrderStrategy 复制代码 1 @Service 2 @OrderTypeAnnotation(orderType = OrderTypeEnum.INSTANT) 3 public class InstantOrderStrategy extends AbstractOrderStrategy { 4 5 @Override 6 public void process(OrderDTO orderDTO) { 7 System.out.println("取消即时订单"); 8 } 9 } 复制代码 4、策略分发处理类 这个类主要是接收业务请求,然后转发到具体的策略类进行处理,这里使用到了spring 获取具体的类,然后通过类上面的注解信息进行转发。 复制代码 1 @Service 2 @Slf4j 3 public class CancelOrderStrategyService { 4 /** 5 * 处理取消逻辑 6 */ 7 public void process(OrderDTO orderDTO) { 8 Map beanMap = SpringBeanUtils.getBeanMap(AbstractOrderStrategy.class); 9 try { 10 for (Map.Entry entry : beanMap.entrySet()) { 11 Object real = SpringBeanUtils.getTarget(entry.getValue()); 12 OrderTypeAnnotation annotation = real.getClass().getAnnotation(OrderTypeAnnotation.class); 13 if (orderDTO.getServiceType() == annotation.orderType().getCode()) { 14 entry.getValue().process(orderDTO); 15 break; 16 } 17 } 18 } catch (Exception e) { 19 log.error("获取目标代理对象失败:{}", e); 20 } 21 } 22 } 复制代码 其中: Map beanMap = SpringBeanUtils.getBeanMap(AbstractOrderStrategy.class); 代表获取AbstractOrderStrategy 下全部子类或接口。 Object real = SpringBeanUtils.getTarget(entry.getValue()); 代表获取具体的代理类 OrderTypeAnnotation annotation = real.getClass().getAnnotation(OrderTypeAnnotation.class); 代表取类上有OrderTypeAnnotation 的注解信息。 CancelOrderStrategyService.process() 这个方法是可以扩展的,通过外部传入的class信息来获取具体的代理类。 5、Spring获取bean工具类 复制代码 1 @Component 2 public class SpringBeanUtils implements ApplicationContextAware { 3 private static ApplicationContext applicationContext; 4 5 @Override 6 public void setApplicationContext(ApplicationContext context) throws BeansException { 7 if (applicationContext == null) { 8 applicationContext = context; 9 } 10 } 11 12 public static Object getBean(String name) { 13 return applicationContext.getBean(name); 14 } 15 16 public static T getBean(Class clazz) { 17 return applicationContext.getBean(clazz); 18 } 19 20 /** 21 * 获取类型为requiredType的Map 22 * 23 * @param clazz 24 * @return 25 */ 26 public static Map getBeanMap(Class clazz) { 27 return applicationContext.getBeansOfType(clazz); 28 } 29 30 /** 31 * 获取 目标对象 32 * 33 * @param proxy 代理对象 34 * @return 目标对象 35 * @throws Exception 36 */ 37 public static Object getTarget(Object proxy) throws Exception { 38 if (!AopUtils.isAopProxy(proxy)) { 39 // 不是代理对象,直接返回 40 return proxy; 41 } 42 43 if (AopUtils.isJdkDynamicProxy(proxy)) { 44 return getJdkDynamicProxyTargetObject(proxy); 45 } else { 46 // cglib 47 return getCglibProxyTargetObject(proxy); 48 } 49 } 50 51 private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception { 52 Field field = proxy.getClass().getSuperclass().getDeclaredField("h"); 53 field.setAccessible(true); 54 AopProxy aopProxy = (AopProxy) field.get(proxy); 55 Field advised = aopProxy.getClass().getDeclaredField("advised"); 56 advised.setAccessible(true); 57 58 Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget(); 59 return target; 60 } 61 62 private static Object getCglibProxyTargetObject(Object proxy) throws Exception { 63 Field field = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0"); 64 field.setAccessible(true); 65 Object dynamicAdvisedInterceptor = field.get(proxy); 66 67 Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); 68 advised.setAccessible(true); 69 70 Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget(); 71 return target; 72 } 73 } 复制代码 6、添加单元测试 复制代码 public class CancelAbstractOrderStrategyTest extends BaseTest { @Autowired private CancelOrderStrategyService cancelOrderStrategyService; @Test public void process() { OrderDTO orderDTO = new OrderDTO(); orderDTO.setServiceType(OrderTypeEnum.INSTANT.getCode()); cancelOrderStrategyService.process(orderDTO); } } 复制代码 7、打印结果: 1 取消即时订单 到了这里代码就已经写完了,如果仔细看的话 应该会明白这里的设计思路,通过策略模式+注解 可以大大的降低业务的耦合度,而且也极大的方便了后期维护的工作量。 部分代码参考:https://www.cnblogs.com/HelloDeveloper/p/11390512.html, 这里对核心类做了修改和精简。 分类: 工作经验, 设计模式 好文要顶 关注我 收藏该文 一枝花算不算浪漫 关注 - 14 粉丝 - 761 +加关注 0 « 上一篇: 工作中常见的设计模式-策略模式 posted @ 2019-09-18 10:13 一枝花算不算浪漫 阅读(88) 评论(0) 编辑 收藏 刷新评论刷新页面返回顶部 注册用户登录后才能发表评论,请 登录 或 注册, 访问 网站首页。 【推荐】超50万C++/C#源码: 大型实时仿真组态图形源码 【活动】京东云限时优惠1.5折购云主机,最高返价值1000元礼品! 【推荐】零基础轻松玩转华为云产品,获壕礼加返百元大礼 【推荐】919 天翼云钜惠,全网低价,云主机9元轻松购 【推荐】华为云文字识别资源包重磅上市,1元万次限时抢购 【推荐】腾讯云海外云服务器1核2G19.8元/月 【福利】git pull && cherry-pick 博客园&华为云百万代金券 相关博文: · 代码重构:用工厂+策略模式优化过多的if else代码块 · 利用策略模式优化过多ifelse代码 · 利用策略模式优化过多ifelse代码 · 细说 Azure Storage 的冗余策略 · 策略模式,重构if-else 最新 IT 新闻: · 十年阿里云栖,云起正当时 · 华为首发计算战略 推出全球最快AI训练集群Atlas900 · 首次亮相中国:希捷全线新SSD登场 · 比尔·盖茨捐赠超350亿美元:但财富丝毫不受影响 · 我国突破高速磁浮列车“动力心脏”关键技术 » 更多新闻... 历史上的今天: 2017-09-18 Java中常见数据结构Map之HashMap 公告 WangMeng's https://www.cnblogs.com/wang-meng/p/11539977.html