责任链/职责链(Chain of Responsibility)模式的定义
为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
责任链模式优缺点
责任链模式是一种对象行为型模式,其主要优点如下。
- 降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
- 增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
- 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
- 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 或 switch-case 语句。
- 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
当过多的if…else分支导致代码难以维护时,考虑使用责任链模式进行业务拆分。
其主要缺点如下。
- 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
- 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
- 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
责任链模式的结构
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
责任链模式结构图
客户端设置责任链图
责任链模式的应用实例
案例一:公司处理员工请假请求
//抽象处理者
public abstract class Handler {
private Handler nextHandler;
// 当前领导能审批通过的最多天数
public int maxDay;
protected Handler(int maxDay) {
this.maxDay = maxDay;
}
// 设置责任链中下一个处理请求的对象
public void setNextHandler(Handler handler) {
nextHandler = handler;
}
protected void handleRequest(int day) {
if (day <= maxDay) {
reply(day);
} else {
if (nextHandler != null) {
// 审批权限不够,交给责任链上的下一个审批者
nextHandler.handleRequest(day);
} else {
System.out.println(day + "天请假,没有更高的领导审批了");
}
}
}
// 交由具体的handler来实现
protected abstract void reply(int day);
}
// 具体处理者-项目经理
public class ProjectManager extends Handler{
public ProjectManager(int maxDay) {
super(maxDay);
}
@Override
protected void reply(int day) {
System.out.println(day+"天请假,项目经理直接审批通过");
}
}
// 具体处理者-部门经理
public class DepartmentHead extends Handler{
public DepartmentHead(int maxDay) {
super(maxDay);
}
@Override
protected void reply(int day) {
System.out.println(day+"天请假,部门经理审批通过");
}
}
//client建立责任链处理请求
public class Client {
public static void main(String[] args) {
Handler handler1 = new ProjectManager(5);
Handler handler2 = new DepartmentHead(10);
handler1.setNextHandler(handler2);
// 总是从链式的首端发起请求
handler1.handleRequest(2);
handler1.handleRequest(3);
handler1.handleRequest(8);
handler1.handleRequest(12);
}
}
/**
2天请假,项目经理直接审批通过
3天请假,项目经理直接审批通过
8天请假,部门经理审批通过
12天请假,没有更高的领导审批了
*/
案例二:销售团队处理客户需求
销售团队的层级关系:
Sales:<=5%
Manager:<=30%
Director:<=40%
Vice President:<=50%
CEO:<=55%
PriceHandler:
/**
* 价格处理人:负责处理客户的折扣申请
* 使用抽象类作为Handler的载体,
* 因为Handler需要有一个指向自身类型的引用,使用interface不方便
* @author HCX
*
*/
public abstract class PriceHandler {
/**
* 直接后继,用于传递请求
* 指向自身类型的引用
* protected:使子类都可以访问到
*/
protected PriceHandler successor;
public void setSuccessor(PriceHandler successor) {
this.successor = successor;
}
/**
* 处理折扣请求
* @param discount
*/
public abstract void processDiscount(float discount);
}
Sales:
/**
* 销售人员,可以批准5%以内的折扣
* @author HCX
*
*/
public class Sales extends PriceHandler {
@Override
public void processDiscount(float discount) {
if(discount <= 0.05){
System.out.format("%s批准了折扣:%.2f%n", this.getClass().getName(),discount);
}else{//让直接后继来处理
successor.processDiscount(discount);
}
}
}
Manager:
/**
* 销售经理,可以批准30%以内的折扣
* @author HCX
*
*/
public class Manager extends PriceHandler{
@Override
public void processDiscount(float discount) {
if(discount <= 0.3){
System.out.format("%s批准了折扣:%.2f%n", this.getClass().getName(),discount);
}else{//超过直接传递给直接后继
successor.processDiscount(discount);
}
}
}
Director:
/**
* 销售总监,可以批准40%以内的折扣
* @author HCX
*
*/
public class Director extends PriceHandler {
@Override
public void processDiscount(float discount) {
if(discount <= 0.4){
System.out.format("%s批准了折扣:%.2f%n", this.getClass().getName(),discount);
}else{//超过直接传递给直接后继
successor.processDiscount(discount);
}
}
}
VicePresident:
/**
* 销售副总裁,可以批准50%以内的折扣
* @author HCX
*
*/
public class VicePresident extends PriceHandler {
@Override
public void processDiscount(float discount) {
if(discount <= 0.5){
System.out.format("%s批准了折扣:%.2f%n", this.getClass().getName(),discount);
}else{//超过直接传递给直接后继
successor.processDiscount(discount);
}
}
}
CEO:
/**
* CEO,可以批准55%以内的折扣
* 折扣超出55%,拒绝申请
* @author HCX
*
*/
public class CEO extends PriceHandler{
@Override
public void processDiscount(float discount) {
if(discount <= 0.55){
System.out.format("%s批准了折扣:%.2f%n", this.getClass().getName(),discount);
}else{//让直接后继来处理
System.out.format("%s拒绝了折扣:%.2f%n", this.getClass().getName(),discount);
}
}
}
PriceHandlerFactory:
public class PriceHandlerFactory {
/**
* 创建PriceHandler的工厂方法
* @return
*/
public static PriceHandler createPriceHandler() {
PriceHandler sales = new Sales();
PriceHandler lead = new Lead();
PriceHandler manager = new Manager();
PriceHandler director = new Director();
PriceHandler vicePresident = new VicePresident();
PriceHandler ceo = new CEO();
//设置直接后继
sales.setSuccessor(lead);
lead.setSuccessor(manager);
manager.setSuccessor(director);
director.setSuccessor(vicePresident);
vicePresident.setSuccessor(ceo);
return sales;
}
}
Customer:
/**
* 客户,请求折扣
* @author HCX
*
*/
public class Customer {
private PriceHandler priceHandler;
public void setPriceHandler(PriceHandler priceHandler) {
this.priceHandler = priceHandler;
}
//只关心折扣请求是否被处理了,不关心被谁处理的。
public void requestDiscount(float discount){
priceHandler.processDiscount(discount);
}
public static void main(String[] args) {
Customer customer = new Customer();
customer.setPriceHandler(PriceHandlerFactory.createPriceHandler());
Random random = new Random();
for(int i=1;i<100;i++){
System.out.println(i+":");
customer.requestDiscount(random.nextFloat());
}
}
}
Customer类只依赖于PriceHandler和PriceHandlerFactory两个类,并没有依赖实现的PriceHandler:Sales和Manager等;因此耦合度较低。
责任链模式的应用实例
BaseCase接口
public interface BaseCase {
// 所有 case 处理逻辑的方法
void doSomething(String input, BaseCase baseCase);
}
责任链处理基类(改进版)
public class CaseChain implements BaseCase {
// 所有 case 列表
private List<BaseCase> mCaseList = new ArrayList<>();
// 索引,用于遍历所有 case 列表
private int index = 0;
// 添加 case
public CaseChain addBaseCase(BaseCase baseCase) {
mCaseList.add(baseCase);
return this;
}
@Override
public void doSomething(String input, BaseCase baseCase) {
// 所有遍历完了,直接返回
if (index == mCaseList.size())
return;
// 获取当前 case
BaseCase currentCase = mCaseList.get(index);
// 修改索引值,以便下次回调获取下个节点,达到遍历效果
index++;
// 调用 当前 case 处理方法
currentCase.doSomething(input, this);
}
}
各个 case 实现接口
public class OneCase implements BaseCase {
@Override
public void doSomething(String input, BaseCase baseCase) {
if ("1".equals(input)) {
// TODO do something
System.out.println(getClass().getName());
return;
}
//当前没法处理,回调回去,让下一个去处理
baseCase.doSomething(input, baseCase);
}
}
public class TwoCase implements BaseCase {
@Override
public void doSomething(String input, BaseCase baseCase) {
if ("2".equals(input)) {
// TODO do something
System.out.println(getClass().getName());
return;
}
//当前没法处理,回调回去,让下一个去处理
baseCase.doSomething(input, baseCase);
}
}
public class DefaultCase implements BaseCase {
@Override
public void doSomething(String input, BaseCase baseCase) {
System.out.println(getClass().getName());
}
}
client建立责任链处理请求
public class Client {
public static void main(String[] args) throws Exception {
String input = "3";
CaseChain caseChain = new CaseChain();
caseChain.addBaseCase(new OneCase())
.addBaseCase(new TwoCase())
.addBaseCase(new DefaultCase());
caseChain.doSomething(input, caseChain);
}
}
/**
com.example.designPattern.chain.improve.DefaultCase
*/