名称
职责链模式(CHAIN OF RESPONSIBILITY)
目的
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
适用性
在以下条件下使用Responsibility 链:
有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
你想在不明确指定接收者的情况下,向多个对象中的一个提交一次请求。
可处理一个请求的对象集合应被动态指定。
结构
处理者(Handle):
定义一个处理请求的接口。
(可选) 实现后继链。
具体处理者(ConcreteHandle):
处理它所负责的请求。
可访问它的后继者。
如果可处理该请求,就处理之;否则将该请求转发给它的后继者。
客户端(Client):向链上的具体处理者(ConcreteHandler)对象提交请求。
协作
当客户提交一个请求时,请求沿链传递直至有一个 ConcreteHandler 对象负责处理它。
效果
优点
降低耦合度。一个具体处理者对象无需知道是其他哪一个对象处理其请求,对象仅需知道该请求会被“正确”地处理。接收者和发送者都没有对方的明确的信息,且链中的对象不需知道链的结构。
职责链可简化对象的相互连接。它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用,减少了对象间的相互连接(依赖),避免使用大量的条件语句(if else等)来确定请求的处理者。
增强了给对象指派职责的灵活性和系统的可扩展性。可以通过在运行时刻对该链进行动态的增加或修改后继者增加或改变处理一个请求的那些职责。可以将这种机制与静态的特例化处理对象的继承机制结合起来使用。
符合单一职责原则。每个类只需要处理自己该处理的工作。
动态指定处理请求的对象。客户端可以在运行时动态创建职责链处理请求,并改变处理请求的顺序。(第三条中有说明)
缺点
不保证被接受。既然一个请求没有明确的接收者,那么就不能保证它一定会被处理 ,该请求可能一直到链的末端都得不到处理。一个请求也可能因该链没有被正确配置而得不到处理。
可能导致性能问题。如果职责链过长,涉及过多的处理对象,可能会降低系统性能。
可能造成循环调用。如果链中的某个节点错误地将请求传回给前一个节点,可能会导致无限循环。
调试困难。当请求未被正确处理时,定位问题所在的具体处理者可能会比较困难。
增加了系统复杂度。对于简单的请求处理逻辑来说,职责链模式可能会引入不必要的复杂度。
应用
问题
小明是一名在读大学生,家里有事需要请假,此时就需要写请假条,然后层层审批,这个审批流程就和职责链很相似。首先定义一个抽象的处理者Leader,包含两个基础属性姓名和后继者(后续审批人),方法handleRequest()用来处理请假条;Leader有四个子类作为具体处理者分别是:辅导员、系主任、院长、校长,重写handleRequest(),方法内部根据请假天数决定自己审批还是向后继者提交,至此,职责链模式形成。
示例
UML
代码示例
基础实体类:请假条,作为审批流程传递的载体
package com.ysj.part5.chainOfResponsibity.normal.entity;
/**
* 请假条
*/
public class LeaveNode {
/** 请假天数 **/
private int number;
/** 请假人 **/
private String person;
public LeaveNode(String person,int number){
this.person = person;
this.number = number;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getPerson() {
return person;
}
public void setPerson(String person) {
this.person = person;
}
}
处理者:领导,setSuccessor()设置后继者,handleRequest()处理请假条
package com.ysj.part5.chainOfResponsibity.normal.handler;
import com.ysj.part5.chainOfResponsibity.normal.entity.LeaveNode;
/**
* 领导(抽象处理者)
*/
public abstract class Leader {
/** 姓名 **/
public String name;
/** 后继者 **/
protected Leader successor;
public Leader(String name){
this.name = name;
}
public void setSuccessor(Leader successor) {
this.successor = successor;
}
public abstract void handleRequest(LeaveNode LeaveNode);
}
具体处理者:辅导员、系主任、院长、校长,重写handleRequest(),每个具体处理者请假天数阈值不同,超出阈值交给后继者处理(校长的画超出直接驳回)
package com.ysj.part5.chainOfResponsibity.normal.concreteHandler;
import com.ysj.part5.chainOfResponsibity.normal.entity.LeaveNode;
import com.ysj.part5.chainOfResponsibity.normal.handler.Leader;
/**
* 辅导员(具体处理者)
*/
public class Instructor extends Leader {
public Instructor(String name) {
super(name);
}
public void handleRequest(LeaveNode LeaveNode) {
if (LeaveNode.getNumber() <= 3) { //小于3天辅导员审批
System.out.println("辅导员" + name + "审批" + LeaveNode.getPerson() + "同学的请假条,请假天数为" + LeaveNode.getNumber() + "天。");
} else { //否则传递给系主任
if (this.successor != null) {
this.successor.handleRequest(LeaveNode);
}
}
}
}
package com.ysj.part5.chainOfResponsibity.normal.concreteHandler;
import com.ysj.part5.chainOfResponsibity.normal.entity.LeaveNode;
import com.ysj.part5.chainOfResponsibity.normal.handler.Leader;
/**
* 系主任(具体处理者)
*/
public class DepartmentHead extends Leader {
public DepartmentHead(String name) {
super(name);
}
public void handleRequest(LeaveNode LeaveNode) {
if (LeaveNode.getNumber() <= 7) { //小于7天系主任审批
System.out.println("系主任" + name + "审批" + LeaveNode.getPerson() + "同学的请假条,请假天数为" + LeaveNode.getNumber() + "天。");
} else { //否则传递给院长
if (this.successor != null) {
this.successor.handleRequest(LeaveNode);
}
}
}
}
package com.ysj.part5.chainOfResponsibity.normal.concreteHandler;
import com.ysj.part5.chainOfResponsibity.normal.entity.LeaveNode;
import com.ysj.part5.chainOfResponsibity.normal.handler.Leader;
/**
* 院长(具体处理者)
*/
public class Dean extends Leader {
public Dean(String name) {
super(name);
}
public void handleRequest(LeaveNode LeaveNode) {
if (LeaveNode.getNumber() <= 10) { //小于10天院长审批
System.out.println("院长" + name + "审批" + LeaveNode.getPerson() + "同学的请假条,请假天数为" + LeaveNode.getNumber() + "天。");
} else { //否则传递给校长
if (this.successor != null) {
this.successor.handleRequest(LeaveNode);
}
}
}
}
package com.ysj.part5.chainOfResponsibity.normal.concreteHandler;
import com.ysj.part5.chainOfResponsibity.normal.entity.LeaveNode;
import com.ysj.part5.chainOfResponsibity.normal.handler.Leader;
/**
* 校长(具体处理者)
*/
public class President extends Leader {
public President(String name) {
super(name);
}
public void handleRequest(LeaveNode LeaveNode) {
if (LeaveNode.getNumber() <= 15) { //小于15天校长长审批
System.out.println("校长" + name + "审批" + LeaveNode.getPerson() + "同学的请假条,请假天数为" + LeaveNode.getNumber() + "天。");
} else { //否则不允批准
System.out.println("请假天天超过15天,不批准...");
}
}
}
客户端:请假人,写请假条并提交
package com.ysj.part5.chainOfResponsibity.normal;
import com.ysj.part5.chainOfResponsibity.normal.concreteHandler.Dean;
import com.ysj.part5.chainOfResponsibity.normal.concreteHandler.DepartmentHead;
import com.ysj.part5.chainOfResponsibity.normal.concreteHandler.Instructor;
import com.ysj.part5.chainOfResponsibity.normal.concreteHandler.President;
import com.ysj.part5.chainOfResponsibity.normal.entity.LeaveNode;
import com.ysj.part5.chainOfResponsibity.normal.handler.Leader;
/**
* 职责链模式
* 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
*
*/
public class Client {
public static void main(String[] args) {
Leader instructor = new Instructor("陈毅"); //辅导员
Leader departmentHead = new DepartmentHead("王明"); //系主任
Leader dean = new Dean("张强"); //院长
Leader president = new President("王晗"); //校长
instructor.setSuccessor(departmentHead); //辅导员的后续者是系主任
departmentHead.setSuccessor(dean); //系主任的后续者是院长
dean.setSuccessor(president); //院长的后续者是校长
//请假3天的请假条
LeaveNode leaveNode1 = new LeaveNode("张三", 3);
instructor.handleRequest(leaveNode1);
//请假9天的请假条
LeaveNode leaveNode2 = new LeaveNode("李四", 9);
instructor.handleRequest(leaveNode2);
//请假15天的请假条
LeaveNode leaveNode3 = new LeaveNode("王五", 15);
instructor.handleRequest(leaveNode3);
//请假20天的请假条
LeaveNode leaveNode4 = new LeaveNode("赵六", 20);
instructor.handleRequest(leaveNode4);
}
}
已知应用
Spring Security
Spring Security 通过 FilterChainProxy 和 FilterSecurityInterceptor 等类实现了职责链模式。FilterChainProxy 作为客户端,负责初始化过滤器链并发送请求;FilterSecurityInterceptor 作为具体处理者,处理安全相关的请求。这种设计使得 Spring Security 的安全性配置非常灵活,可以在运行时动态地配置和修改过滤器链。
评论区