行为型设计模式之《责任链模式》实践

简介: 责任链模式(Chain Of Responsibility Pattern)顾名思义,就是为请求创建一条处理链路,链路上的每个处理器都判断是否可以处理请求,如果不能处理则往后走,依次从链头走到链尾,直到有处理器可以处理请求。

1. 定义

责任链模式(Chain Of Responsibility Pattern)顾名思义,就是为请求创建一条处理链路,链路上的每个处理器都判断是否可以处理请求,如果不能处理则往后走,依次从链头走到链尾,直到有处理器可以处理请求。

2. 类型

2.1 请求只处理一次

每个节点都有机会处理请求,但是请求只要处理成功就结束了。

场景

流程审批、扑克牌

代码示例

原来

publicclassApply {
publicbooleanapply(intrequireDay) {
if (requireDay<=1) {
returntrue;
        } elseif (requireDay<=3) {
applyByLeader(requireDay);
        } else {
applyByManager(requireDay);
        }
    }
publicbooleanapplyByLeader(intrequireDay) {
//...    }
publicbooleanapplyByManager(intrequireDay) {
//...    }
}

改造后

BaseHandler.java

publicabstractclassBaseHandler {
protectedBaseHandlersuccessor;
publicvoidsetSuccessor(BaseHandlersuccessor) {
this.successor=successor;
    }
publicabstractbooleanapply(intrequireDay);
publicvoidprint() {
System.out.println(this.getClass().getSimpleName() +" process.");
    }
}

AutoHandler.java

publicclassAutoHandlerextendsBaseHandler {
@Overridepublicbooleanapply(intrequireDay) {
super.print();
if (requireDay<=1) {
returntrue;
        }
returnsuccessor.apply(requireDay);
    }
}

LeaderHandler.java

publicclassLeaderHandlerextendsBaseHandler {
@Overridepublicbooleanapply(intrequireDay) {
super.print();
if (requireDay<=3) {
returntrue;
        }
returnsuccessor.apply(requireDay);
    }
}

ManagerHandler.java

publicclassManagerHandlerextendsBaseHandler {
privatestaticfinalintMAX_DAY=996;
@Overridepublicbooleanapply(intrequireDay) {
super.print();
returnrequireDay<=MAX_DAY;
    }
}

HandlerClient.java

publicclassHandlerClient {
privatestaticfinalAutoHandlerAUTO_HANDLER;
static {
ManagerHandlermanagerHandler=newManagerHandler();
LeaderHandlerleaderHandler=newLeaderHandler();
leaderHandler.setSuccessor(managerHandler);
AUTO_HANDLER=newAutoHandler();
AUTO_HANDLER.setSuccessor(leaderHandler);
    }
publicstaticvoidmain(String[] args) {
AUTO_HANDLER.apply(1);
System.out.println();
AUTO_HANDLER.apply(3);
System.out.println();
AUTO_HANDLER.apply(5);
    }
}

输出:

AutoHandler process.

AutoHandler process.


LeaderHandler process.

AutoHandler process.


LeaderHandler process.

ManagerHandler process.

2.2 请求处理多次

每个节点都有机会处理请求,节点处理完之后继续往后走,直到链尾。

场景

  • 过滤器 / 拦截器
  • JavaEE 的 Servlet 规范定义的 Filter

代码示例

请求如果成功通过 process 处理,则进入下一个 process,如果不通过则被过滤掉,这里不再累述代码。

3. 项目实践

有个根据配置构造ODPS查询语句的代码,配置片段如下:

{
"name": "Document no",
"code": "service_order_code",
"isBasicField": true,
"fromRerating": false,
"classType": "java.lang.String"}

原来是通过 if-else 来实现的,代码如下所示:

现在要新增非空校验的字段 notNull,现在配置如下:

{
"name": "Document no",
"code": "service_order_code",
"isBasicField": true,
"fromRerating": false,
"classType": "java.lang.String",
"notNull": true}

发现又得往 if-else 里面硬塞分支,有代码洁癖的我怎么能容忍自己写这种代码?最近也从同事那里了解到责任链模式的厉害之处,索性直接给它优化掉,这里我截取下关键代码片段。

首先声明抽象处理类

/*** 责任链抽象处理器*/publicabstractclassAbstractHandler<T, V> {
protectedAbstractHandler<T, V>successor;
publicvoidsetSuccessor(AbstractHandler<T, V>handler) {
this.successor=handler;
    }
/*** 处理方法** @param context 上下文* @return R*/publicabstractStringprocess(Context<T, V>context);
}

各具体处理类安排上

/*** 责任链入口,扩展字段处理*/publicclassFirstExtendFieldHandlerextendsAbstractHandler<AdjustmentTemplateDTO, String> {
/*** 处理方法** @param context 上下文* @return R*/@OverridepublicStringprocess(Context<AdjustmentTemplateDTO, String>context) {
AdjustmentTemplateDTOrequest=context.getRequest();
if (!request.getBasicField()) {
StringtmpField=request.getFromRerating() ?String.format(GET_JSON_OBJECT, NEW_PARAM, PREFIX+request.getCode()) :
String.format(GET_JSON_OBJECT, OLD_PARAM, PREFIX+request.getCode());
context.setResult(tmpField);
        }
returnsuccessor.process(context);
    }
}
/*** 非空字段处理器*/publicclassSecondNotNullFieldHandlerextendsAbstractHandler<AdjustmentTemplateDTO, String> {
/*** 处理方法** @param context 上下文* @return R*/@OverridepublicStringprocess(Context<AdjustmentTemplateDTO, String>context) {
AdjustmentTemplateDTOrequest=context.getRequest();
if (!request.getBasicField()) {
returnsuccessor.process(context);
        }
if (request.getNotNull() ==null||!request.getNotNull()) {
StringtmpField= (request.getFromRerating() ?NEW : OLD) +request.getCode();
context.setResult(tmpField);
returnsuccessor.process(context);
        } else {
StringoldValue=OLD+request.getCode();
context.setResult(oldValue);
oldValue=successor.process(context);
StringnewValue=NEW+request.getCode();
context.setResult(newValue);
newValue=successor.process(context);
StringfinalField=String.format(OdpsConstants.IF, oldValue, newValue, oldValue);
context.setResult(finalField);
returnfinalField;
        }
    }
}
/*** 时间字段处理*/publicclassThirdTimeFormatHandlerextendsAbstractHandler<AdjustmentTemplateDTO, String> {
@OverridepublicStringprocess(Context<AdjustmentTemplateDTO, String>context) {
AdjustmentTemplateDTOrequest=context.getRequest();
StringfinalSql=StringUtils.isNotBlank(request.getTimeFormat())
?String.format(TIMESTAMP_FORMAT, context.getResult(), request.getTimeFormat())
            : context.getResult();
context.setResult(finalSql);
returnfinalSql;
    }
}

最后是负责初始化责任链的客户端

/*** 责任链客户端*/publicclassHandlerChainClient {
privatestaticfinalFirstExtendFieldHandlerFIRST_HANDLER;
static {
ThirdTimeFormatHandlerthirdHandler=newThirdTimeFormatHandler();
SecondNotNullFieldHandlersecondHandler=newSecondNotNullFieldHandler();
secondHandler.setSuccessor(thirdHandler);
FIRST_HANDLER=newFirstExtendFieldHandler();
FIRST_HANDLER.setSuccessor(secondHandler);
    }
/*** 调用责任链进行处理** @param request 请求参数* @return result*/publicstaticStringprocess(AdjustmentTemplateDTOrequest) {
AdjustmentContextcontext=newAdjustmentContext();
context.setRequest(request);
returnFIRST_HANDLER.process(context);
    }
}

最后,业务代码里又臭又长的 if-else 变成了一行代码。

HandlerChainClient.process(request);

4. 优点

  • 解耦。请求发送者无需知道请求在何时、何处以及如何被处理,实现了发送者与处理者的解耦。
  • 灵活、可插拔。可以看到想要添加一个处理流程,只需实现BaseHandler,然后注入到对应的位置即可;删除一个流程也是一样,只需要将本节点的位置替换成下一个节点即可,客户端无需感知处理器的变化。
  • 代码优雅,责任链相比 if-else 是更加优雅的。

5. 缺点

  • 类的数量变多了,组链时要注意避免出现环状结构,导致出现死循环。


目录
相关文章
|
25天前
|
设计模式 算法 开发者
探索编程语言中的设计模式:从理论到实践
设计模式,这一编程世界中的灯塔,为无数开发者照亮了复杂问题解决的道路。本文将深入探讨设计模式在编程实践中的运用,以代码示例揭示其背后的智慧。无论你是初学者还是资深开发者,都能在这里找到启发和共鸣。让我们一起领略设计模式的魅力,开启编程世界的新篇章!
|
1月前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
Kotlin - 改良设计模式 - 责任链模式
42 3
|
1月前
|
设计模式 监控 算法
Python编程中的设计模式应用与实践感悟###
在Python这片广阔的编程疆域中,设计模式如同导航的灯塔,指引着开发者穿越复杂性的迷雾,构建出既高效又易于维护的代码结构。本文基于个人实践经验,深入探讨了几种核心设计模式在Python项目中的应用策略与实现细节,旨在为读者揭示这些模式背后的思想如何转化为提升软件质量的实际力量。通过具体案例分析,展现了设计模式在解决实际问题中的独特魅力,鼓励开发者在日常编码中积极采纳并灵活运用这些宝贵的经验总结。 ###
|
2月前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
Kotlin - 改良设计模式 - 责任链模式
58 9
|
27天前
|
设计模式 JavaScript Scala
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
26 0
|
27天前
|
设计模式 开发者 Python
Python编程中的设计模式应用与实践感悟####
本文作为一篇技术性文章,旨在深入探讨Python编程中设计模式的应用价值与实践心得。在快速迭代的软件开发领域,设计模式如同导航灯塔,指引开发者构建高效、可维护的软件架构。本文将通过具体案例,展现设计模式如何在实际项目中解决复杂问题,提升代码质量,并分享个人在实践过程中的体会与感悟。 ####
|
2月前
|
设计模式 API 持续交付
深入理解微服务架构:设计模式与实践
【10月更文挑战第19天】介绍了微服务架构的核心概念、设计模式及最佳实践。文章详细探讨了微服务的独立性、轻量级通信和业务能力,并介绍了聚合器、链式和发布/订阅等设计模式。同时,文章还分享了实施微服务的最佳实践,如定义清晰的服务边界、使用API网关和服务发现机制,以及面临的挑战和职业心得。
|
1月前
|
设计模式 JavaScript Scala
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
39 0
|
2月前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
本教程详细讲解了Kotlin语法,适合需要深入了解Kotlin的开发者。对于希望快速上手Kotlin的读者,推荐查阅“简洁”系列教程。本文通过学生会经费申请的例子,介绍了责任链模式及其在Kotlin中的实现,并使用偏函数进行了改进,使代码更加简洁和灵活。
19 0
|
2月前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
Kotlin - 改良设计模式 - 责任链模式
42 0