Java设计模式-责任链模式

Java版本:jdk1.8

IDE:IDEA

一 前言

本文介绍责任链模式以及Java下的实现.

二 概念

1.什么是责任链模式

责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。

在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

责任链模式: 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的额偶合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止.

2.使用场景

在JavaWeb中 过滤器链的实现,实际上就是一种责任链模式

3.优缺点

优点:

降低耦合度。它将请求的发送者和接收者解耦。

简化了对象。使得对象不需要知道链的结构。

增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。

增加新的请求处理类很方便。

缺点:

不能保证请求一定被接收。

系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。

可能不容易观察运行时的特征,有碍于除错。

三 代码实现

定义一个抽象类AbstractChainHandler

/**
* 责任链抽象类
* @author hyl
* @date 2020/03/14
*/
public abstract class AbstractChainHandler {
private AbstractChainHandler next;
protected abstract T doHandler(Object... obj);
public T handler(Object... obj) {
T result = doHandler(obj);
if (!isAccordWith(result) && next != null) {
return (T) next.handler(obj);
} else {
return result;
}
}
public void setNext(AbstractChainHandler next){
this.next = next;
}
/**
* 判断逻辑
*
* @return
*/
protected boolean isAccordWith(T t) {
return false;
}
}
定义具体实现类ConcreteChainHandler1
/**
* @author hyl
* @date 2020/3/14 10:42 下午
*/
public class ConcreteChainHandler1 extends AbstractChainHandler {
protected T doHandler(Object... obj) {
//具体业务逻辑
return null;
}
}
``ConcreteChainHandler2`
/**
* @author hyl
* @date 2020/3/14 10:42 下午
*/
public class ConcreteChainHandler2 extends AbstractChainHandler {
protected T doHandler(Object... obj) {
//具体业务逻辑
return null;
}
}
接下来就是具体的装配以及使用
public static void main(String[] args) {
AbstractChainHandler h1 = new ConcreteChainHandler1();
AbstractChainHandler h2 = new ConcreteChainHandler2();
h1.setNext(h2);
h1.handler(new Object[]{});
}

现在看起来手动装配责任链next的方式很蠢,但是配合控制反转以及部分注解,就能在框架中自动装配了,后续会实现基于Spirng的责任链模式以及基于SpringBoot的责任链模式.

四 简单例子

利用责任链模式实现一个请假审批流程.假设请假需要组长审批通过,再主管审批通过,最后CEO审批通过后才算请假成功.也就是说前一个审批不通过,后面的就不用再审批了.

先定义一个审批抽象类ApprovalChainHandler
/**
* 请假审批任链抽象类
* @author hyl
* @date 2020/03/14
*/
public abstract class ApprovalChainHandler {
private ApprovalChainHandler next;
protected abstract boolean doHandler(String name);
public boolean handler(String name) {
boolean result = doHandler(name);
if (isAccordWith(result) && next != null) {
return next.handler(name);
} else {
return result;
}
}
public void setNext(ApprovalChainHandler next){
this.next = next;
}
/**
* 判断审批是否同意
*
* @return
*/
protected boolean isAccordWith(boolean t) {
return t;
}
}

再定义3个审批角色类 :组长审批/主管审批/CEO审批

组长审批类GroupLeaderChainHandler

/**
* @author hyl
* @date 2020/3/15 10:04 上午
*/
public class GroupLeaderChainHandler extends ApprovalChainHandler {
protected boolean doHandler(String name) {
boolean result= new Random().nextBoolean();
System.out.println("组长审批["+ name +"]结果::"+result);
return result;
}
}
主管审批类ExecutiveChainHandler
/**
* @author hyl
* @date 2020/3/15 10:04 上午
*/
public class ExecutiveChainHandler extends ApprovalChainHandler {
protected boolean doHandler(String name) {
boolean result= new Random().nextBoolean();
System.out.println("主管审批["+ name +"]结果: "+result);
return result;
}
}
CEO审批类 CEOChainHandler
/**
* @author hyl
* @date 2020/3/15 10:04 上午
*/
public class CEOChainHandler extends ApprovalChainHandler {
protected boolean doHandler(String name) {
boolean result= new Random().nextBoolean();
System.out.println("CEO审批["+ name +"]结果:: "+result);
return result;
}
}
在使用责任链进行处理前的时候,要定义好链的执行顺序,在这里审批的顺序是 组长->主管->CEO
ApprovalChainHandler h1 = new GroupLeaderChainHandler();
ApprovalChainHandler h2 = new ExecutiveChainHandler();
ApprovalChainHandler h3 = new CEOChainHandler();
h1.setNext(h2);
h2.setNext(h3);
之后就能直接使用h1.handler()进行审批了
public static void main(String[] args) {
ApprovalChainHandler h1 = new GroupLeaderChainHandler();
ApprovalChainHandler h2 = new ExecutiveChainHandler();
ApprovalChainHandler h3 = new CEOChainHandler();
h1.setNext(h2);
h2.setNext(h3);
String staff1 = "张三";
String staff2 = "李四";
String staff3 = "王五";
System.out.println(staff1+"请假结果:"+h1.handler(staff1));
System.out.println(staff2+"请假结果:"+h1.handler(staff2));
System.out.println(staff3+"请假结果:"+h1.handler(staff3));
}

输出结果:

组长审批[张三]结果::false

张三请假结果:false

组长审批[李四]结果::true

主管审批[李四]结果: true

CEO审批[李四]结果:: false

李四请假结果:false

组长审批[王五]结果::true

主管审批[王五]结果: false

王五请假结果:false

这样就完成了一个责任链模式的实现以及使用.

五 Spring下责任链的实现

1. 定义Bean

同样是上面的请假例子,先定义一个请假审批责任链抽象类ApprovalChainHandler

/**
* 请假审批任链抽象类
*
* @author hyl
* @date 2020/03/14
*/
public abstract class ApprovalChainHandler {
private ApprovalChainHandler next;
protected abstract boolean doHandler(String name);
public boolean handler(String name) {
boolean result = doHandler(name);
if (isAccordWith(result) && next != null) {
return next.handler(name);
} else {
return result;
}
}
public void setNext(ApprovalChainHandler next) {
this.next = next;
}
/**
* 判断审批是否同意
*
* @return
*/
protected boolean isAccordWith(boolean t) {
return t;
}
}

可以发现和之前的抽象类一模一样

再定义3个不同角色的处理类

组长审批类GroupLeaderChainHandler

@Component
@Order(1)
public class GroupLeaderChainHandler extends ApprovalChainHandler {
protected boolean doHandler(String name) {
boolean result= new Random().nextBoolean();
System.out.println("组长审批["+ name +"]结果::"+result);
return result;
}
}
主管审批类ExecutiveChainHandler
@Component
@Order(2)
public class ExecutiveChainHandler extends ApprovalChainHandler {
protected boolean doHandler(String name) {
boolean result= new Random().nextBoolean();
System.out.println("主管审批["+ name +"]结果: "+result);
return result;
}
}
CEO审批类CEOChainHandler
@Component
@Order(3)
public class CEOChainHandler extends ApprovalChainHandler {
protected boolean doHandler(String name) {
boolean result= new Random().nextBoolean();
System.out.println("CEO审批["+ name +"]结果:: "+result);
return result;
}
}

能发现3个审批类逻辑部分也和之前一模一样,只是都加上了2个注解 @Component和@Order.

@Component作用是借助spring的IOC自动生成并初始化单例Bean,@Order的作用则是在接下来组装责任链顺序的依据

2 定义Configuration 配置责任链

完成责任链的Component还不够,还需要在Config里组装好它.

ApprovalChainHandlerConfig
@Configuration
public class ApprovalChainHandlerConfig {
private ApprovalChainHandler approvalChainHandler;
@Autowired
private List approvalChainHandlers;
@PostConstruct
private void initChainHandler(){
Collections.sort(approvalChainHandlers, AnnotationAwareOrderComparator.INSTANCE);
int size = approvalChainHandlers.size();
for(int i=0;i
if(i == size-1){
approvalChainHandlers.get(i).setNext(null);
}else{
approvalChainHandlers.get(i).setNext(approvalChainHandlers.get(i+1));
}
}
if(size>0) {
approvalChainHandler = approvalChainHandlers.get(0);
}
}
@Bean("leaveChainHandler")
public ApprovalChainHandler approvalChainHandler(){
return approvalChainHandler;
}
}
@Order注解的作用在
Collections.sort(approvalChainHandlers, AnnotationAwareOrderComparator.INSTANCE);

这里被使用到,它会根据order注解的值的大小进行排序,实际上AnnotationAwareOrderComparator.INSTANCE的作用远不止这点,感兴趣可以查看它的源码实现.

3.测试

我们编写一个外部调用接口来测试下结果

@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
@Qualifier("leaveChainHandler")
private ApprovalChainHandler approvalChainHandler;
@RequestMapping("/leave")
public Boolean askForLeave(String name){
return approvalChainHandler.handler(name);
}
}

然后能在控制台上显示

组长审批[张三]结果::true

主管审批[张三]结果: false

最后请求返回到的也就是false

六 总结

以上就是责任链模式基本的用法. 责任链也被称作职责链,每一个职责都能被定义成一个处理对象. 使用责任链模式能够帮助我们在业务代码中更优雅地实现非互斥的多if判断.在需要扩展的时候也能更加轻松.

七 思考:如何实现一个能批量处理的责任链?

前置条件: 如何实现一个能批量处理的责任链?

假设现在有100名员工同时发起请假申请,以List nameList发起请求

每个责任链实例都会从数据库查询该name的数据

如果以 nameList.forEach(name->handler.handler(name)),name它就会有100次的数据库查询.其处理的性能就不高了.