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

简介: 责任链模式(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. 缺点

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


目录
相关文章
|
16天前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
Kotlin - 改良设计模式 - 责任链模式
53 9
|
15天前
|
设计模式 API 持续交付
深入理解微服务架构:设计模式与实践
【10月更文挑战第19天】介绍了微服务架构的核心概念、设计模式及最佳实践。文章详细探讨了微服务的独立性、轻量级通信和业务能力,并介绍了聚合器、链式和发布/订阅等设计模式。同时,文章还分享了实施微服务的最佳实践,如定义清晰的服务边界、使用API网关和服务发现机制,以及面临的挑战和职业心得。
|
28天前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发中,设计模式是提高代码可维护性、扩展性和复用性的关键技术之一。本文将通过探讨单例模式,一种最常用的设计模式,来揭示其在PHP中的应用及优势。单例模式确保一个类仅有一个实例,并提供一个全局访问点。通过实际案例,我们将展示如何在PHP项目中有效实现单例模式,以及如何利用这一模式优化资源配置和管理。无论是PHP初学者还是经验丰富的开发者,都能从本文中获得有价值的见解和技巧,进而提升自己的编程实践。
|
4天前
|
设计模式 JavaScript Scala
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
13 0
|
27天前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的深入解析与实践
【10月更文挑战第9天】 策略模式是一种行为设计模式,它允许在运行时选择算法的行为。在PHP开发中,通过使用策略模式,我们可以轻松切换算法或逻辑处理方式而无需修改现有代码结构。本文将深入探讨策略模式的定义、结构以及如何在PHP中实现该模式,并通过实际案例展示其应用价值和优势。
28 1
|
29天前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的深入解析与实践
在PHP开发中,设计模式是提高代码可读性、可维护性和扩展性的重要工具。本文将深入探讨策略模式这一行为型设计模式,通过分析其定义、结构、使用场景以及在PHP中的实际应用,帮助开发者更好地理解和运用策略模式来优化自己的项目。不同于传统摘要的简洁概述,本文摘要部分将详细阐述策略模式的核心理念和在PHP中的实现方法,为读者提供清晰的指引。
|
15天前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
本教程详细讲解了Kotlin语法,适合需要深入了解Kotlin的开发者。对于希望快速上手Kotlin的读者,推荐查阅“简洁”系列教程。本文通过学生会经费申请的例子,介绍了责任链模式及其在Kotlin中的实现,并使用偏函数进行了改进,使代码更加简洁和灵活。
11 0
|
18天前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
Kotlin - 改良设计模式 - 责任链模式
36 0
|
18天前
|
设计模式 开发者 Python
Python编程中的设计模式应用与实践###
【10月更文挑战第18天】 本文深入探讨了Python编程中设计模式的应用与实践,通过简洁明了的语言和生动的实例,揭示了设计模式在提升代码可维护性、可扩展性和重用性方面的关键作用。文章首先概述了设计模式的基本概念和重要性,随后详细解析了几种常用的设计模式,如单例模式、工厂模式、观察者模式等,在Python中的具体实现方式,并通过对比分析,展示了设计模式如何优化代码结构,增强系统的灵活性和健壮性。此外,文章还提供了实用的建议和最佳实践,帮助读者在实际项目中有效运用设计模式。 ###
11 0
|
24天前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的深入解析与实践
【10月更文挑战第12天】 在软件开发的世界中,设计模式是解决常见问题的最佳实践。它们不是具体的代码,而是一种编码和设计经验的总结。在PHP开发中,合理运用设计模式可以极大地提高代码的可维护性、扩展性和复用性。本文将深入探讨策略模式(Strategy Pattern)的原理、实现方式及其在PHP中的应用。通过具体示例,我们将展示如何利用策略模式来解耦算法与对象,从而让代码更加灵活和易于管理。
16 0