❝本文收录在我的博客:www.chengxy-nds.top,技术资源共享,一块儿进步web
❞
最近公司貌似融到资了!开始发了疯似的找渠道推广,如今终于明白为啥前一段大肆的招人了,原来是在下一盘大棋,对员工总的来看是个好事,或许是时候该跟boss提一提涨工资的话题了。算法
不过,涨工资还没下文,随之而来的倒是一车一车的需求,天天都有新渠道接入,并且每一个渠道都要提供个性化支持,开发量陡增。最近都没什么时间更文,准点下班都成奢望了!设计模式
因为推广渠道的激增,而每个下单来源在下单时都作特殊的逻辑处理,可能每两天就会加一个来源,已经把以前的下单逻辑改的面目全。出于长远的考虑,我决定对现有的逻辑进行重构,毕竟长痛不如短痛。安全
咱们看下边的伪代码,大体就是重构前下单逻辑的代码,因为来源比较少,简单的作if-else
逻辑判断足以知足需求。编辑器
如今每种订单来源的处理逻辑都有几百行代码,看着已经比较臃肿,可我愣是迟迟没动手重构,一方面业务方总像催命鬼同样的让你赶工期,想快速实现需求,这样写是最快;另外一方面是不敢动,面对古董
级代码,仍是想求个安稳。ide
但此次来源一会儿增长几十个,再用这种方式作已经没法维护了,想象一下那种臃肿的if-else
代码,别说开发想一想都头大!工具
public class OrderServiceImpl implements IOrderService {
@Override public String handle(OrderDTO dto) { String type = dto.getType(); if ("1".equals(type)) { return "处理普通订单"; } else if ("2".equals(type)) { return "处理团购订单"; } else if ("3".equals(type)) { return "处理促销订单"; } return null; } } 复制代码
思来想去基于当前业务场景重构,仍是用策略模式比较合适,它是oop
中比较著名的设计模式之一,对方法行为的抽象。oop
策略模式定义了一个拥有共同行为的算法族,每一个算法都被封装起来,能够互相替换,独立于客户端而变化。post
if-else
或者
switch-case
来选择具体子类时。
这个是用策略模式修改后代码:性能
@Component
@OrderHandlerType(16) public class DispatchModeProcessor extends AbstractHandler{ @Autowired private OrderStencilledService orderStencilledService; @Override public void handle(OrderBO orderBO) { //订单完结广播通知(1 - 支付完成) orderStencilledService.dispatchModeFanout(orderBO); // SCMS 出库单 orderStencilledService.createScmsDeliveryOrder(orderBO.getPayOrderInfoBO().getLocalOrderNo()); } } 复制代码
每一个订单来源都有本身单独的逻辑实现类,而每次须要添加订单来源,直接新建实现类,修改@OrderHandlerType(16)
的数值便可,不再用去翻又臭又长的if-lese
。
不只如此在分配任务时,每一个人负责开发几种订单来源逻辑,均可以作到互不干扰,并且很大程度上减小了合并代码的冲突。
定义一个标识订单来源的注解@OrderHandlerType
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface OrderHandlerType { int value() default 0; } 复制代码
向上抽象出来一个具体的业务处理器
public abstract class AbstractHandler {
abstract public void handle(OrderBO orderBO); } 复制代码
handler
入口@Component
@SuppressWarnings({"unused","rawtypes"}) public class HandlerProcessor implements BeanFactoryPostProcessor { private String basePackage = "com.ecej.order.pipeline.processor"; public static final Logger log = LoggerFactory.getLogger(HandlerProcessor.class); @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { Map<Integer,Class> map = new HashMap<Integer,Class>(); ClassScaner.scan(basePackage, OrderHandlerType.class).forEach(x ->{ int type = x.getAnnotation(OrderHandlerType.class).value(); map.put(type,x); }); beanFactory.registerSingleton(OrderHandlerType.class.getName(), map); log.info("处理器初始化{}", JSONObject.toJSONString(beanFactory.getBean(OrderHandlerType.class.getName()))); } } 复制代码
public class ClassScaner { private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); private final List<TypeFilter> includeFilters = new ArrayList<TypeFilter>(); private final List<TypeFilter> excludeFilters = new ArrayList<TypeFilter>(); private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver); //添加包含的Fiter public void addIncludeFilter(TypeFilter includeFilter) { this.includeFilters.add(includeFilter); } //添加排除的Fiter public void addExcludeFilter(TypeFilter excludeFilter) { this.excludeFilters.add(excludeFilter); } //扫描指定的包,获取包下全部的Class public static Set<Class<?>> scan(String basePackage, Class<?>... targetTypes) { ClassScaner cs = new ClassScaner(); for (Class<?> targetType : targetTypes){ if(TypeUtils.isAssignable(Annotation.class, targetType)){ cs.addIncludeFilter(new AnnotationTypeFilter((Class<? extends Annotation>) targetType)); }else{ cs.addIncludeFilter(new AssignableTypeFilter(targetType)); } } return cs.doScan(basePackage); } //扫描指定的包,获取包下全部的Class public static Set<Class<?>> scan(String[] basePackages, Class<?>... targetTypes) { ClassScaner cs = new ClassScaner(); for (Class<?> targetType : targetTypes){ if(TypeUtils.isAssignable(Annotation.class, targetType)){ cs.addIncludeFilter(new AnnotationTypeFilter((Class<? extends Annotation>) targetType)); }else{ cs.addIncludeFilter(new AssignableTypeFilter(targetType)); } } Set<Class<?>> classes = new HashSet<Class<?>>(); for (String s : basePackages){ classes.addAll(cs.doScan(s)); } return classes; } //扫描指定的包,获取包下全部的Class public Set<Class<?>> doScan(String [] basePackages) { Set<Class<?>> classes = new HashSet<Class<?>>(); for (String basePackage :basePackages) { classes.addAll(doScan(basePackage)); } return classes; } //扫描指定的包,获取包下全部的Class public Set<Class<?>> doScan(String basePackage) { Set<Class<?>> classes = new HashSet<Class<?>>(); try { String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath( SystemPropertyUtils.resolvePlaceholders(basePackage))+"/**/*.class"; Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath); for (int i = 0; i < resources.length; i++) { Resource resource = resources[i]; if (resource.isReadable()) { MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); if ((includeFilters.size() == 0 && excludeFilters.size() == 0)|| matches(metadataReader)) { try { classes.add(Class.forName(metadataReader.getClassMetadata().getClassName())); } catch (ClassNotFoundException ignore) {} } } } } catch (IOException ex) { throw new RuntimeException("I/O failure during classpath scanning", ex); } return classes; } private boolean matches(MetadataReader metadataReader) throws IOException { for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return false; } } for (TypeFilter tf : this.includeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return true; } } return false; } } 复制代码
@Component public class HandlerContext { @Autowired private ApplicationContext beanFactory; public AbstractHandler getInstance(Integer type){ Map<Integer,Class> map = (Map<Integer, Class>) beanFactory.getBean(OrderHandlerType.class.getName()); return (AbstractHandler)beanFactory.getBean(map.get(type)); } } 复制代码
我这里是在接受到MQ消息时,处理多个订单来源业务,不一样订单来源路由到不一样的业务处理类中。
@Component @RabbitListener(queues = "OrderPipelineQueue") public class PipelineSubscribe{ private final Logger LOGGER = LoggerFactory.getLogger(PipelineSubscribe.class); @Autowired private HandlerContext HandlerContext; @Autowired private OrderValidateService orderValidateService; @RabbitHandler public void subscribeMessage(MessageBean bean){ OrderBO orderBO = JSONObject.parseObject(bean.getOrderBO(), OrderBO.class); if(null != orderBO &&CollectionUtils.isNotEmpty(bean.getType())) { for(int value:bean.getType()) { AbstractHandler handler = HandlerContext.getInstance(value); handler.handle(orderBO); } } } } 复制代码
接收实体 MessageBean
类代码
public class MessageBean implements Serializable {
private static final long serialVersionUID = 5454831432308782668L; private String cachKey; private List<Integer> type; private String orderBO; public MessageBean(List<Integer> type, String orderBO) { this.type = type; this.orderBO = orderBO; } } 复制代码
以上设计模式方式看着略显复杂,很些小伙伴提出质疑:“你为了个if-else
,弄的如此的麻烦,又是自定义注解,又弄这么多类不麻烦吗?” 还有一些小伙伴纠结于性能问题,策略模式的性能可能确实不如if-else
。
但我以为吧增长一点复杂度、牺牲一丢丢性能,换代码的整洁和可维护性仍是值得的。不过,一我的一个想法,怎么选仍是看具体业务场景吧!
IOC容器
和
依赖注入
的方式来解决。
如下是订单来源策略类的一部分,不得不说策略类确实比较多。
凡事都有他的两面性,if-else
多层嵌套和也都有其各自的优缺点:
if-else
的优势就是简单,想快速迭代功能,逻辑嵌套少且不会持续增长,if-else
更好些,缺点也是显而易见,代码臃肿繁琐不便于维护。
策略模式
将各个场景的逻辑剥离出来维护,同一抽象类有多个子类,须要使用if-else
或者 switch-case
来选择具体子类时,建议选策略模式,他的缺点就是会产生比较多的策略类文件。
两种实现方式各有利弊,如何选择仍是要依据具体业务场景,仍是那句话设计模式不是为了用而用,必定要用在最合适的位置。
日常和粉丝私下聊天,好多人对于学设计模式的感觉:设计模式背了一大堆,可日常开发还不是整天写if-else
业务逻辑,根本就用不到。
学设计模式也不是用不到,只是有时候没有合适它的场景而已,像咱们今天说的这种业务场景,用设计模式就能够完美的解决嘛。
学了N多技术可工做用不到是一种很常见的事情,一个稳定的项目使用一种技术会有诸多考量的,新技术会不会提高系统复杂度?它有哪些性能瓶颈?这些都必须考虑到,毕竟项目稳定才是最重要,谁也不敢轻易冒险尝试。
而咱们学习技术可不只为了眼下项目中是否会用到,是要作一个技术积累,作长远打算,人往高处走,没点能力可不行。
原创不易,燃烧秀发输出内容,但愿你能有一丢丢收获!
整理了几百本各种技术电子书,送给小伙伴们。关公众号回复【「666」】自行领取。和一些小伙伴们建了一个技术交流群,一块儿探讨技术、分享技术资料,旨在共同窗习进步,若是感兴趣就扫码加入咱们吧!