设计模式之职责链(责任链)模式(Chain of Responsibility Pattern)

在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生活中的“击鼓传花”游戏等。

在计算机软硬件中也有相关例子,如总线网中数据报传送,每台计算机根据目标地址是否同自己的地址相同来决定是否接收;还有异常处理中,处理程序根据异常的类型决定自己是否处理该异常;还有 Struts2 的拦截器、JSP 和 Servlet 的 Filter 等,所有这些,如果用责任链模式都能很好解决。

在这里插入图片描述

一、定义与特点

1.1、定义:

责任链模式,也叫职责链模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。这过程实际上是一个 递归调用

注意:责任链模式也叫职责链模式,是一种对象行为型模式。

1.2、要点

1、多个对象,共同处理一个任务。
2、这些对象使用链式存储结构,形成一个链,每个对象知道自己的下一个对象。
3、一个对象对任务进行处理,可以添加一些操作后将对象传递个下一个任务。也可以在此对象上结束任务的处理,并结束任务。
4、客户端负责组装链式结构,但是客户端不需要关心最终是谁来处理了任务。

在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,所以责任链将请求的发送者和请求的处理者解耦了。

1.3、优点:

  1. 职责链模式的最主要功能就是:动态组合,请求者和接受者解耦。

  2. 请求者和接受者松散耦合:请求者不需要知道接受者,也不需要知道如何处理。每个职责对象只负责自己的职责范围,其他的交给后继者。各个组件间完全解耦。

  3. 动态组合职责:职责链模式会把功能分散到单独的职责对象中,然后在使用时动态的组合形成链,从而可以灵活的分配职责对象,也可以灵活的添加改变对象职责。

1.4、缺点:

  1. 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
  2. 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
  3. 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

二、模式的结构与实现

通常情况下,可以通过 数据链表 来实现职责链模式的数据结构。

2.1、主要角色:

  1. Handler(抽象处理者):定义一个处理请求的接口,包含抽象处理方法和一个后继处理者。
  2. ConcreteHandler(具体处理者):实现 Handler 的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  3. Client(客户类):创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

2.2、UML类图

在这里插入图片描述

三、职责链模式解决采购审批

3.1、需求:

采购员采购教学器材,

  1. 如果金额 小于等于 5000元,由教学主任审批 ;
  2. 如果金额 小于等于 10000元, 由院长审批 ;
  3. 如果金额 小于等于 30000元. ,由副校长1 ;
  4. 如果金额 超过 30000 元以上,有校长审批 。

3.2、图解

在这里插入图片描述

3.3、UML类图

在这里插入图片描述

3.4、代码

3.4.1、Handler( 抽象处理者)
/**
 * Handler( 抽象处理者)
 */
public abstract class Approver {

	/** 下一个处理者 */
	Approver nextApprover;
	
	/** 名字 */
	String name;

	public Approver(String name) {
		this.name = name;
	}

	/**
	 * 下一个处理者
	 * 
	 * @param nextApprover
	 */
	public void setApprover(Approver nextApprover) {
		this.nextApprover = nextApprover;
	}

	/**
	 * 处理审批请求的方法,得到一个请求, 处理是子类完成,因此该方法做成抽象
	 * 
	 * @param purchaseRequest
	 */
	public abstract void processRequest(PurchaseRequest purchaseRequest);

}
3.4.2、ApproverForDepart(教学主任)
/**
 * 教学主任
 * 
 * <pre>
 * 如果金额 小于等于5000, 由教学主任审批
 * </pre>
 */
public class ApproverForDepart extends Approver {

	public ApproverForDepart(String name) {
		super(name);
	}

	@Override
	public void processRequest(PurchaseRequest purchaseRequest) {
		if (purchaseRequest.getPrice() <= 5000) {
			System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
		} else {
			nextApprover.processRequest(purchaseRequest);
		}
	}

}
3.4.3、ApproverForCollege(院长)
/**
 * 院长
 * 
 * <pre>
 * 如果金额 小于等于10000, 由院长审批
 * </pre>
 */
public class ApproverForCollege extends Approver {

	public ApproverForCollege(String name) {
		super(name);
	}

	@Override
	public void processRequest(PurchaseRequest purchaseRequest) {
		if (purchaseRequest.getPrice() < 5000 && purchaseRequest.getPrice() <= 10000) {
			System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
		} else {
			nextApprover.processRequest(purchaseRequest);
		}
	}
}
3.4.4、ApproverForViceSchoolMaster(副校长)
/**
 * 副校长
 * 
 * <pre>
 * 如果金额 小于等于30000, 由副校长审批
 * </pre>
 */
public class ApproverForViceSchoolMaster extends Approver {

	public ApproverForViceSchoolMaster(String name) {
		super(name);
	}

	@Override
	public void processRequest(PurchaseRequest purchaseRequest) {
		if (purchaseRequest.getPrice() < 10000 && purchaseRequest.getPrice() <= 30000) {
			System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
		} else {
			nextApprover.processRequest(purchaseRequest);
		}
	}
}
3.4.5、ApproverForSchoolMaster(校长)
/**
 * 校长
 * 
 * <pre>
 * 如果金额 超过30000以上,有审批
 * </pre>
 */
public class ApproverForSchoolMaster extends Approver {

	public ApproverForSchoolMaster(String name) {
		super(name);
	}

	@Override
	public void processRequest(PurchaseRequest purchaseRequest) {
		if (purchaseRequest.getPrice() > 30000) {
			System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
		} else {
			nextApprover.processRequest(purchaseRequest);
		}
	}
}
3.4.6、PurchaseRequest(请求类)
/**
 * 请求类
 */
public class PurchaseRequest {

	private int type = 0; // 请求类型
	private float price = 0.0f; // 请求金额
	private int id = 0;

	// 构造器
	public PurchaseRequest(int type, float price, int id) {
		this.type = type;
		this.price = price;
		this.id = id;
	}

	public int getType() {
		return type;
	}

	public float getPrice() {
		return price;
	}

	public int getId() {
		return id;
	}

}
3.4.7、Client
public class Client {

	public static void main(String[] args) {
		// 创建一个请求
		PurchaseRequest purchaseRequest = new PurchaseRequest(1, 31000, 1);

		// 创建相关的审批人
		ApproverForDepart departmentApprover = new ApproverForDepart("张主任");
		ApproverForCollege collegeApprover = new ApproverForCollege("李院长");
		ApproverForViceSchoolMaster viceSchoolMasterApprover = new ApproverForViceSchoolMaster("王副校");
		ApproverForSchoolMaster schoolMasterApprover = new ApproverForSchoolMaster("佟校长");

		// 需要将各个审批级别的下一个设置好 (处理人构成环形: )
		departmentApprover.setApprover(collegeApprover);
		collegeApprover.setApprover(viceSchoolMasterApprover);
		viceSchoolMasterApprover.setApprover(schoolMasterApprover);
		schoolMasterApprover.setApprover(departmentApprover);// 设置环状

		// 从 教学主任 开始审批
		// departmentApprover.processRequest(purchaseRequest);

		// 从 佟校长 ,开始审批,由于是环状,依然可以审批
		viceSchoolMasterApprover.processRequest(purchaseRequest);
	}

}
3.4.8、运行结果:
 请求编号 id= 1 被 佟校长 处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值