概述
基本介绍
1、职责链模式Chain of Responsibility Pattern,也叫做责任链模式,为请求创建了一个接收者对象的链,责任链模式对请求的发送者和接收这进行解耦。这种模式属于行为型模式。
2、职责连模式通常每个接收者对象都包含对另一个接收者的引用,如果一个对象不能处理该请求,那么他会把相同的请求传给下一个接收者。以此类推。
3、在一个软件系统中,可以处理某个请求的对象不止一个,例如学校OA系统中,教学办公用品的采购,教学主任、副校长、校长都可以处理,他们构成一条处理采购请求的链式结构,那么这条链就可以理解为责任链。通常情况下,责任链是直线型,也就是沿着一条单向的链来传递请求,不过责任链也可以是环状或者树状结构。
4、责任链模式可以将请求的处理者组织成一条链,链上的每一个对象都是请求处理者,并让请求沿着链进行传递,有链上的处理者对请求进行相应的处理,客户端无须关注请求的处理细节以及请求的传递,只需将请求发到链上即可。
原理类图
类图角色分析
1、Handler:抽象处理者,它定义了一个处理请求的抽象方法,同时包含一个另外的Handler,形成一个链条。一般设计为抽象类。
2、ConcreteHandler:具体处理者,它是抽象处理者的子类,实现了抽象处理者定义的抽象请求处理方法,在处理请求之前需要判断,是否有相应的权限处理该请求,如果可以处理就直接处理,如果不能处理,转发给后继者,在具体处理者中可以访问来责任链中的下一个对象,以便请求的转发。
3、Request,请求类,包含很多属性,表示一个请求。
案例
需求:学校OA系统中,教学办公用品的采购,教学主任、副校长、校长都可以处理。
代码实现
package com.example.pattern.chain;
import lombok.Getter;
import lombok.Setter;
import java.util.Random;
/**
* 职责连模式
* 需求 学校OA采购审批
* 教学主任 Education Director 审批权限 0 ~ 3000
* 副校长 vice-principal 3000 ~ 10000
* 校长 principal > 10000
*
* @author zjt
*/
@Setter
@Getter
class PurchaseRequest {
private int number;// 采购编号
private double price; // 采购金额
private String purpose; // 采购用途
public PurchaseRequest(double price, String purpose) {
this.number = new Random().nextInt(1000);
this.price = price;
this.purpose = purpose;
}
}
@Getter
public abstract class Approver {
protected String name; // 名字
private Approver nextApprover; // 下一个处理者
public Approver(String name) {
this.name = name;
}
public void setNextApprover(Approver nextApprover) { // 设置后继处理者
this.nextApprover = nextApprover;
}
// 抽象处理请求方法
public abstract void processRequest(PurchaseRequest request);
}
class EducationDirectorApprover extends Approver {
public EducationDirectorApprover(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest request) {
double price = request.getPrice();
if (price < 3000) {
System.out.println("请求编号:" + request.getNumber() + "请求被\t" + name + "\t处理,金额为:" + price);
} else {
getNextApprover().processRequest(request);
}
}
}
class VicePrincipalApprover extends Approver {
public VicePrincipalApprover(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest request) {
double price = request.getPrice();
if (3000 <= price && price < 10000) {
System.out.println("请求编号:" + request.getNumber() + "请求被\t" + name + "\t处理,金额为:" + price);
} else {
getNextApprover().processRequest(request);
}
}
}
class PrincipalApprover extends Approver {
public PrincipalApprover(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest request) {
double price = request.getPrice();
if (10000 <= price) {
System.out.println("请求编号:" + request.getNumber() + "请求被\t" + name + "\t处理,金额为:" + price);
}else {
getNextApprover().processRequest(request);
}
}
}
class Client {
public static void main(String[] args) {
Approver educationDirector = new EducationDirectorApprover("教学主任");
Approver vicePrincipalApprover = new VicePrincipalApprover("副校长");
Approver principalApprover = new PrincipalApprover("校长");
// 创建责任链
educationDirector.setNextApprover(vicePrincipalApprover);
vicePrincipalApprover.setNextApprover(principalApprover);
// 校长处理,但是金额小于 10000 直接转交给 其它角色去处理 构成一个环状
principalApprover.setNextApprover(educationDirector);
// 创建采购单
for (int i = 1; i <= 5 ; i++) {
int i1 = i * 2000;
PurchaseRequest request = new PurchaseRequest(i1, "采购书籍");
educationDirector.processRequest(request);
}
}
}
总结
优点
1、将请求和处理分开,实现解耦,提高系统灵活性。简化了链的对象,使对象不需要知道链的结构。对象仅需知道该请求会被处理即可,接收者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度。
2、请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接。
3、 在给对象分派职责时,职责链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责。
4、在系统中增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可,从这一点来看是符合“开闭原则”的。
缺点
1、由于一个请求没有明确的接收者,那么就不能保证它一定会被处理,该请求可能一直到链的末端都得不到处理;一个请求也可能因职责链没有被正确配置而得不到处理。
2、对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,而且在进行代码调试时不太方便。
3、如果责任链创建不当,可能会造成循环调用,将导致栈溢出报错。