Java设计模式综合运用(门面+模版方法+责任链+策略)

引言:很久没有更新了,主要是工作忙。最近,工作中一个子系统升级,把之前不易扩展的缺点给改进了一下,主要是运用了几个设计模式进行稍微改造了一下。

1.项目背景

在公司的一个实际项目中,需要做一个第三方公司(以下简称GMG)的系统集成工作,把该公司的一些订单数据集成到自己公司平台下,各个订单具有一些共性,但是也有其特有的特征。 经过设计,目前我把订单分为POLICY和BOB类型(暂且这么说吧,反正就是一种订单类型,大家参照着看就OK)。

在订单数据集成到公司平台前,需要对订单数据进行一些必要的业务逻辑校验操作,并且每个订单都有自己的校验逻辑(包含公共的校验逻辑)。 本节介绍的便是整个订单集成系统中的校验逻辑在综合利用设计模式的基础上进行架构设计。

2.校验逻辑

本校验逻辑主要分为四个部分:

  1. 校验文件名称(RequestValidator.validateFileInfo)
  2. 校验文件内容中的概要部分(RequestValidator.validateSummary)
  3. 校验文件内容中的列名称(RequestValidator.validateHeaders)
  4. 校验文件内容中的明细(RequestValidator.validateDetails)
    其实上面的RequestValidator的实现逻辑最后都是委托给RequestValidationFacade这个门面类进行相应的校验操作。

3.实现细节

3.1 domain介绍

主要分为RequestFile和RequestDetail两个domain,RequestFile接收泛型的类型(即RequestFile), 使得其子类能够自动识别相应的RequestDetail的子类。RequestFile为抽象类,定义了以下抽象方法,由子类实现:

//由子类实现具体的获取文件明细内容
public abstract List<T> getRequestDetails();
//由子类实现具体的获取workflow的值
public abstract WorkflowEnum getProcessWorkFlow();
//由子类实现文件列字段名列表
public abstract String[] getDetailHeaders();

RequestDetail及其子类就是workflow对应文件的明细内容。

3.2 WorkflowEnum枚举策略

本例中如下规定:

  1. workflow为WorkflowEnum.POLICY对应文件名为:csync_policy_yyyyMMdd_HHmmss_count.txt
  2. 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相应的子类对象,其实也是隐藏着【策略模式】的影子。

类图如下:


门面模式

3.3.2 模版方法模式

在具体的校验逻辑中,用到核心设计模式便是模版方法模式,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();

以上抽象方法就类似我们常说的钩子函数,由子类实现即可。类图如下图所示:


模版方法模式

3.3.3 责任链模式

在AbstractRequestValidation抽象类中有个抽象方法validateFileDetails,校验的是文件的明细内容中的相应业务规则,此为核心校验, 较为复杂,而且针对每个业务流程,其校验逻辑相差较大,在此处,利用了责任链模式进行处理。

Validator为校验器的父接口,包含两个泛型参数(即:<R extends RequestDetail,F extends RequestFile>),其实现类可以方便的转换需要校验的文件明细。

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)。

类图如下图所示:


责任链模式1-validator chain

责任链模式2-部分validator

3.3.4 策略模式

如果单单从上面的校验器实现上来看,如果需要增加一个校验器,就需要在AbstractRequestValidation的子类方法validateFileDetails中添加,然后进行相应的校验操作。这样就会非常的麻烦,没有做到真正的解耦。 此时,策略模式就发挥到了可以动态选择某种校验策略的作用(Validator的实现类就是一个具体的校验策略)。

AbstractValidatorHandler抽象类持有FileDetailValidatorChain类的对象,并且实现累Spring的一个接口ApplicationListener(是为了Spring容器启动完成的时候自动把相应的校验器加入到校验器链中)。 核心就是WorkflowEnum这个策略枚举的作用,在子类可以动态的取得相应的校验器对象。

根据子类提供需要的校验器所在的包名列表和不需要的校验器列表,动态配置出需要的校验器链表。核心实现逻辑如下:

private void addValidators() {
    List<Class<? extends Validator>> 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 Set<String> getBasePackages();

/**
 * the classes need to be excluded
 * @return
 */
protected abstract Set<Class> excludeClasses();

事例代码地址https://github.com/landy8530/DesignPatterns

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,292评论 18 399
  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,818评论 1 15
  • 参考资料:菜鸟教程之设计模式 设计模式概述 设计模式(Design pattern)代表了最佳的实践,通常被有经验...
    Steven1997阅读 1,123评论 1 12
  • 我们浪费掉了太多的青春,那是一段如此自以为是又如此狼狈不堪的青春岁月。有欢笑也有泪水,有朝气也有颓废,有甜蜜也有荒...
    阿准先生阅读 420评论 3 4
  • 夜风很好,尽管到家已经快11点了,我还是想去跑两圈。 一、或者逆流,不要害怕 到体育公园的时候,最后几个跑步的人三...
    阿不快跑阅读 368评论 7 3