Java设计模式之行为型模式(一):责任链模式

一、简介

责任链模式(Chain of Responsibility),又称职责链模式,它属于行为型模式。通过责任链模式,你可以为某个请求创建一个接收者对象链。每个接收者对象依序检查此请求,并对其进行处理,如果该对象不能处理该请求或者处理完成后,就将它传递给链中的下一个接收者对象。

责任链模式的原理UML类图如下图所示:
在这里插入图片描述

责任链模式的角色介绍:

  • Handler:抽象的处理者,定义了一个处理请求的接口。
  • ConcreteHandler1,2:具体的处理者,处理它负责的请求,如果它处理不了,请将请求交给它的后继者(下一个处理者进行处理请求),从而形成一个责任链。
  • 客户类:负责创建责任链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

二、使用

1.场景

学校OA系统的采购审批模块中,采购员需要采购教学器材时,有着以下要求:

  1. 如果0<金额<=5000,由教学主任审批
  2. 如果5000<金额<=10000,由院长审批
  3. 如果10000<金额<=30000,由副校长审批
  4. 如果金额大于30000,就由校长审批

2.UML类图设计

根据上述的需求采用责任链设计模式来设计程序,程序的UML类图如下:
在这里插入图片描述
说明:Approver审批员的角色为抽象处理者,而PurchaseRequest为购买请求实体类。

3.代码实现

抽象处理者Approver类的代码如下:

//抽象审批者
public abstract class Approver {

	Approver approver;// 下一个审批者
	String name;// 名字

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

	/**
	 * @param approver 设置下一个审批者
	 */
	public void setApprover(Approver approver) {
		this.approver = approver;
	}

	// 处理请求审批的方法,由子类实现
	public abstract void processRequest(PurchaseRequest purchaseRequest);

}

四个具体的处理者,CollegeApprover类等的实现代码:

public class CollegeApprover extends Approver {

	public CollegeApprover(String name) {
		// TODO Auto-generated constructor stub
		super(name);
	}

	@Override
	public void processRequest(PurchaseRequest purchaseRequest) {
		// TODO Auto-generated method stub
		if (purchaseRequest.getPrice() >= 5000 && purchaseRequest.getPrice() < 10000) {
			System.out.println("请求编号" + purchaseRequest.getId() + "被" + this.name + "处理了");
		} else {
			approver.processRequest(purchaseRequest);
		}

	}
}

public class DepartmentApprover extends Approver {
	public DepartmentApprover(String name) {
		// TODO Auto-generated constructor stub
		super(name);
	}

	@Override
	public void processRequest(PurchaseRequest purchaseRequest) {
		// TODO Auto-generated method stub
		if (purchaseRequest.getPrice() < 5000) {
			System.out.println("请求编号" + purchaseRequest.getId() + "被" + this.name + "处理了");
		} else {
			approver.processRequest(purchaseRequest);
		}

	}

}

public class SchoolMasterApprover extends Approver {

	public SchoolMasterApprover(String name) {
		// TODO Auto-generated constructor stub
		super(name);
	}

	@Override
	public void processRequest(PurchaseRequest purchaseRequest) {
		// TODO Auto-generated method stub
		if (purchaseRequest.getPrice() >= 30000) {
			System.out.println("请求编号" + purchaseRequest.getId() + "被" + this.name + "处理了");
		} else {
			approver.processRequest(purchaseRequest);
		}

	}
}
public class ViceSchoolMasterApprover extends Approver {

	public ViceSchoolMasterApprover(String name) {
		// TODO Auto-generated constructor stub
		super(name);
	}

	@Override
	public void processRequest(PurchaseRequest purchaseRequest) {
		// TODO Auto-generated method stub
		if (purchaseRequest.getPrice() >= 10000 && purchaseRequest.getPrice() < 30000) {
			System.out.println("请求编号" + purchaseRequest.getId() + "被" + this.name + "处理了");
		} else {
			approver.processRequest(purchaseRequest);
		}

	}
}

购买请求实体类PurchaseRequest的实现代码:

//购买请求实体类
public class PurchaseRequest {

	private int id;
	private String type;
	private float price;

	public PurchaseRequest(int id, String type, float price) {
		super();
		this.id = id;
		this.type = type;
		this.price = price;
	}
//省略getter、setter
}

最后,在客户类Client创建和设置处理请求的责任链,代码实现如下:

public class Client {
	public static void main(String[] args) {
		PurchaseRequest purchaseRequest = new PurchaseRequest(1, "教材", 15000);

		DepartmentApprover departmentApprover = new DepartmentApprover("张主任");
		CollegeApprover collegeApprover = new CollegeApprover("李院长");
		ViceSchoolMasterApprover viceSchoolMasterApprover = new ViceSchoolMasterApprover("王副校长");
		SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("赵校长");

		departmentApprover.setApprover(collegeApprover);
		collegeApprover.setApprover(viceSchoolMasterApprover);
		viceSchoolMasterApprover.setApprover(schoolMasterApprover);
		schoolMasterApprover.setApprover(departmentApprover);

		departmentApprover.processRequest(purchaseRequest);

	}
}

请求购买金额为15000的教材进行测试,程序运行结果:
在这里插入图片描述

三、责任链模式在Tomcat中的应用

首先先复习一下Tomcat的整体架构:

(1)Tomcat整体架构分析

首先是Tomcat 的模块分层结构图,如下图所示:

在这里插入图片描述
Tomcat这六大模块中Catalina容器是Tomcat的核心,其他的模块都是为Catalina容器提供支撑的,比如:通过Coyote模块提供链接通信,Jasper模块提供JSP引擎,Naming提供JNDI服务,Juli提供日志服务。
其中Catalina的主要组件结构如下图所示:
图2Catalina的主要组件结构

如上图所示,Catalina管理Server,而Server表示整个服务器,Server下面有多个服务Service,每个服务都包含有多个(Coyote实现的)连接器组件Connector和一个容器组件Container。
在Tomcat启动时,会初始化一个Catalina实例,负责解析Tomcat的配置文件,以此来创建服务器Server组件,并根据命令来对其进行管理。其中的Server,负责组装并启动Servlet引擎,Tomcat连接器等组件,Server通过实现Lifecycle接口,提供了一种优雅的启动和关闭整个系统的方式。其中Container的结构包含了4种容器,分别是Engine、Host、Context和Wrapper,这四个容器之间不是平行关系,而是包含关系。
容器关系结构如下图所示:
在这里插入图片描述

(2)Tomcat中的责任链模式

在Tomcat中请求的处理流程和过滤器Filter的调用设计都采用的是责任链模式,这个设计模式是Tomcat中Container容器设计的基础,父子容器就是通过一条链连接在一起。这条链一直将请求正确的传递给最终处理请求的那个Servlet。从Engine到Host再到Context一直到Wrapper都是通过一个链传递请求。各容器中的管道Pipeline同样通过其中的阀门valve传递请求。

Tomcat中关于容器中处理请求的流程涉及的责任链模式的关键类图,如下图所示:
在这里插入图片描述
从上图中,我们可以看到每一个容器都会有一个Pipeline,而一个Pipeline又会具有多个Valve阀门,其中StandardEngine对应的阀门是StandardEngineValve,StandardHost对应的阀门是StandardHostValve,StandardContext对应的阀门是StandardContextValve,StandardWrapper对应的阀门是StandardWrapperValve。这里每一Pipeline就好比一个管道,而每一Valve就相当于一个阀门,一个管道可以有多个阀门,而对于阀门来说有两种,一种阀门在处理完自己的事情以后,只需要将工作委托给下一个和自己在同一管道的阀门即可,第二种阀门是负责衔接各个管道的,它负责将请求传递给下个管道的第一个阀门处理,而这种阀门叫Basic阀门,它是每个管道中最后一个阀门,上面的命名为Standard开头的Valve都属于第二种阀门。其中AccessLogValve则属于第一种阀门,AccessLogValve是在默认Host容器中默认提供的valve。这点可以在server.xml中能够知道,如下图所示:
在这里插入图片描述

AccessLogValve是请求访问日志阀门,通过此阀门可以记录所有客户端的访问日志,包括远程主机IP、远程主机名、请求方法、请求协议、会话id、请求时间、处理时长、数据包大小等等。它提供了任意参数化的配置,可以通过任意组合来定制你的访问日志格式。另外ErrorReportValve同样属于第一种阀门,这是一个将错误以html格式输出的阀门。
Tomcat中关于容器Host中处理请求的流程涉及的责任链模式的关键时序图,如下图所示:
在这里插入图片描述

通过上图,我们可以很清楚的了解到Tomcat的请求处理流程中容器之间调用的过程。当用户请求服务器的时候,EndPoint会接受请求,Processor中从Socket连接中根据http协议解析出对应的数据,构造Request和Response对象,通过CoyoteAdapter将Request和Response对象转化为HttpServletRequest和HttpServleResponse对象,然后传递给后面的容器处理。
顶层容器是StandardEngine,StandardEngine处理请求其实是通过容器的Pipeline进行的,而Pipeline其实最终是通过管道上的各个阀门进行的,当请求到达StandardEngineValve的时候,此阀门会将请求转发给对应StandardHost的Pipeline的第一个阀门处理,然后以此最终到达StandardHostValve阀门,后面过程图中省略了,后面的过程是它又会将请求转发给StandardContext的Pipeline的第一个阀门,这样以此类推,最后到达StandardWrapperValve,此阀门会根据Request来构建对应的Servlet,并将请求转发给对应的HttpServlet处理。
从这里我们可以看出其实Tomcat核心请求处理流程就是通过责任链一步步的组装起来的。

四、总结

(1)责任链模式的优点:

  • 将请求的发送者和接收者解耦
  • 可以简化你的对象,因为它不需要知道链的结构。
  • 通过改变链内的成员或调动它们的次序,允许你动态地新增或者删除责任。
  • 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。

(2)责任链模式的缺点

  • 并不保证请求一定会被执行,如果没有任何对象处理它的话,它可能会落到责任链尾端都没有得到处理。
  • 可以不容易观察运行时的特征,有碍于发现错误。
  • 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
  • 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

(3)责任链模式的用途

  • 有多个对象可以处理一个请求,哪个对象处理该请求由运行时刻自动确定。
  • 可动态指定一组对象处理请求,或添加新的处理者。
  • 在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。

参考:责任链模式(职责链模式)详解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值