摘要:此案例中,门面类为,然后各个门面方法的参数均为抽象类,通过决定调用中的哪个子类。抽象类持有类的对象,并且实现累的一个接口是为了容器启动完成的时候自动把相应的校验器加入到校验器链中。
引言:很久没有更新了,主要是工作忙。最近,工作中一个子系统升级,把之前不易扩展的缺点给改进了一下,主要是运用了几个设计模式进行稍微改造了一下。1.项目背景
本文也同步发布至简书,地址: https://www.jianshu.com/p/962...
在公司的一个实际项目中,需要做一个第三方公司(以下简称GMG)的系统集成工作,把该公司的一些订单数据集成到自己公司平台下,各个订单具有一些共性,但是也有其特有的特征。 经过设计,目前我把订单分为POLICY和BOB类型(暂且这么说吧,反正就是一种订单类型,大家参照着看就OK)。
在订单数据集成到公司平台前,需要对订单数据进行一些必要的业务逻辑校验操作,并且每个订单都有自己的校验逻辑(包含公共的校验逻辑)。 本节介绍的便是整个订单集成系统中的校验逻辑在综合利用设计模式的基础上进行架构设计。
2.校验逻辑本校验逻辑主要分为四个部分:
校验文件名称(RequestValidator.validateFileInfo)
校验文件内容中的概要部分(RequestValidator.validateSummary)
校验文件内容中的列名称(RequestValidator.validateHeaders)
校验文件内容中的明细(RequestValidator.validateDetails)
其实上面的RequestValidator的实现逻辑最后都是委托给RequestValidationFacade这个门面类进行相应的校验操作。
3.实现细节 3.1 domain介绍主要分为RequestFile和RequestDetail两个domain,RequestFile接收泛型的类型(即RequestFile), 使得其子类能够自动识别相应的RequestDetail的子类。RequestFile为抽象类,定义了以下抽象方法,由子类实现:
//由子类实现具体的获取文件明细内容 public abstract ListgetRequestDetails(); //由子类实现具体的获取workflow的值 public abstract WorkflowEnum getProcessWorkFlow(); //由子类实现文件列字段名列表 public abstract String[] getDetailHeaders();
RequestDetail及其子类就是workflow对应文件的明细内容。
3.2 WorkflowEnum枚举策略本例中如下规定:
workflow为WorkflowEnum.POLICY对应文件名为:csync_policy_yyyyMMdd_HHmmss_count.txt
workflow为WorkflowEnum.BOB对应文件名为:csync_bob_integration_yyyyMMdd_HHmmss_count.txt
以上校验逻辑在AbstractRequestValidation类相应的子类中实现(validateFileName方法),其实这个枚举贯穿整个校验组件,它就是一个针对每个业务流程定义的一个枚举策略。
3.3 涉及到的设计模式实现思路 3.3.1 门面模式在客户端调用程序中,采用门面模式进行统一的入口(门面模式讲究的是脱离具体的业务逻辑代码)。门面模式封装的结果就是避免高层模块深入子系统内部,同时提供系统的高内聚、低耦合的特性。
此案例中,门面类为RequestValidationFacade,然后各个门面方法的参数均为抽象类RequestFile,通过RequestFile->getProcessWorkFlow()决定调用AbstractRequestValidation中的哪个子类。 AbstractRequestValidation类构造方法中定义了如下逻辑:
requestValidationHandlerMap.put(this.accessWorkflow(),this.accessBeanName());
把子类中Spring自动注入的实体bean缓存到requestValidationHandlerMap中,key即为WorkflowEnum枚举值,value为spring bean name, 然后在门面类中可以通过对应的枚举值取得BeanName,进而得到AbstractRequestValidation相应的子类对象,进行相应的校验操作。
注:这边动态调用到AbstractRequestValidation相应的子类对象,其实也是隐藏着【策略模式】的影子。
类图如下:
在具体的校验逻辑中,用到核心设计模式便是模版方法模式,AbstractRequestValidation抽象类中定义了以下抽象方法:
/** * validate the file details * @param errMsg * @param requestFile * @return */ protected abstract StringBuilder validateFileDetails(StringBuilder errMsg,RequestFile requestFile); /** * validate the file name * @param fileName * @return */ protected abstract String validateFileName(String fileName); /** * return the current CSYNC_UPDATE_WORKFLOW.UPDATE_WORKFLOW_ID * @return */ protected abstract WorkflowEnum accessWorkflow(); /** * return the current file name"s format ,such as: csync_policy_yyyyMMdd_HHmmss_count.txt * @return */ protected abstract String accessFileNameFormat(); /** * return the subclass"s spring bean name * @return */ protected abstract String accessBeanName();
以上抽象方法就类似我们常说的钩子函数,由子类实现即可。类图如下图所示:
在AbstractRequestValidation抽象类中有个抽象方法validateFileDetails,校验的是文件的明细内容中的相应业务规则,此为核心校验, 较为复杂,而且针对每个业务流程,其校验逻辑相差较大,在此处,利用了责任链模式进行处理。
Validator为校验器的父接口,包含两个泛型参数(即:
String doValidate(R detail, F file, ValidatorChain chain) throws BusinessValidationException;
该方法含有一个ValidatorChain参数,就自然而然的为该校验器形成一个链条提供便利条件。
ValidatorChain为校验器链,含有两个接口方法:
String doValidate(T requestDetail, F requestFile) throws BusinessValidationException; ValidatorChain addValidator(Validator validator, WorkflowEnum workflowId);
该处有一个addValidator方法,为ValidatorChain对象添加校验器的方法,返回本身。对应于每个业务流程需要哪些校验器就在此实现即可(即AbstractRequestValidation的子类方法validateFileDetails)。
类图如下图所示:
如果单单从上面的校验器实现上来看,如果需要增加一个校验器,就需要在AbstractRequestValidation的子类方法validateFileDetails中添加,然后进行相应的校验操作。这样就会非常的麻烦,没有做到真正的解耦。 此时,策略模式就发挥到了可以动态选择某种校验策略的作用(Validator的实现类就是一个具体的校验策略)。
AbstractValidatorHandler抽象类持有FileDetailValidatorChain类的对象,并且实现累Spring的一个接口ApplicationListener(是为了Spring容器启动完成的时候自动把相应的校验器加入到校验器链中)。 核心就是WorkflowEnum这个策略枚举的作用,在子类可以动态的取得相应的校验器对象。
根据子类提供需要的校验器所在的包名列表和不需要的校验器列表,动态配置出需要的校验器链表。核心实现逻辑如下:
private void addValidators() { List> validators = getValidators(); validators.forEach((validator) -> { String simpleName = validator.getSimpleName(); String beanName = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1); LOGGER.info("Added validator:{},spring bean name is:{}",simpleName,beanName); Validator validatorInstance = ApplicationUtil.getApplicationContext().getBean(beanName,validator); fileDetailValidatorChain.addValidator(validatorInstance,getWorkflowId()); }); }
具体实现可以参考github代码即可。
该类含有以下几个抽象方法:
protected abstract WorkflowEnum getWorkflowId(); /** * the package need to be added the validators * @return */ protected abstract SetgetBasePackages(); /** * the classes need to be excluded * @return */ protected abstract Set excludeClasses();
事例代码地址:https://github.com/landy8530/...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/74532.html
摘要:注解方式优点使用注解方式可以极大的减少使用模版方法模式带来的扩展时需要继承模版类的弊端,工厂注解的方式可以无需关心其他业务类的实现,而且减少了类膨胀的风险。 在上一篇文章Java设计模式综合运用(门面+模版方法+责任链+策略)中,笔者写了一篇门面模式、模版方法、责任链跟策略模式的综合运用的事例文章,但是后来笔者发现,在实现策略模式的实现上,发现了一个弊端:那就是如果在后续业务发展中,需...
摘要:责任链模式的具体运用以及原理请参见笔者责任链模式改进方式引入适配器模式关于接口适配器模式原理以及使用场景请参见笔者适配器模式。 1 责任链模式现存缺点 由于责任链大多数都是不纯的情况,本案例中,只要校验失败就直接返回,不继续处理接下去责任链中的其他校验逻辑了,故而出现如果某个部分逻辑是要由多个校验器组成一个整理的校验逻辑的话,则此责任链模式则显现出了它的不足之处了。(责任链模式的具体运...
摘要:当然,除了让我们显得更加专业之外,在自己所学习或者工作的项目中,适当合理的使用设计模式,能够给项目带来很大的好处。 简单说两句 本文首发公众号【一名打字员】 对不住各位老铁了,年前说好要更几波JAVA的东西,又偷懒了,没办法,在这里用小锤锤偷偷锤了自己几下。由于工作原因,更新时间不定,各位老铁有问题可以私聊我哈。 对于初学者或者是正在向中高级的Java程序猿(打字员)来说,时刻梳理自己...
摘要:能够协调调用者和被调用者,能够在一定程度上降低系统的耦合性。特点低耦合性,独立性好,安全性应用客户访问不到或者被访问者希望隐藏自己,所以通过代理来访问自己。 我们接着上面的几种模式继续讲: 4、组合模式 将对象组合成树形结构表示部分-整体的层次结构。 特点:灵活性强 应用:对象的部分-整体的层次结构,模糊组合对象和简单对象处理问题 代码实现 /** 组合模式* *///继承模式clas...
摘要:抽象工厂模式是为了处理对象具有等级结构以及对象族的问题。单例设计模式单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类成为单例类。 导语:设计模式是无数码农前人在实际的生产项目中经过不断的踩坑、爬坑、修坑的经历总结出来的经验教训,经过抽象之后表达成的概念。能够帮助后来的设计者避免重复同样的错误或者弯路。我也抽空整理了一下设计模式,用自己的话总结了一下,自认...
阅读 825·2021-09-22 15:17
阅读 1871·2021-09-22 15:06
阅读 2152·2021-09-08 09:35
阅读 5041·2021-09-01 11:43
阅读 3427·2019-08-30 15:55
阅读 2135·2019-08-30 12:48
阅读 3132·2019-08-30 12:45
阅读 1762·2019-08-29 17:31