设计模式-责任链模式
什么是责任链模式
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
意图
解耦合。避免请求发送者与接收者耦合在一起,让多个接收者都有可能接收请求,将这些接收者连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。下游接收者没有资格处理就传给它的上游接收者。
主要解决
职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
在简单的说就是:责任链是面向对象的实现,我们把多个情况拆封成多个接受者对象,根据顺序依次判断是接受者否有权限处理,如果有则处理,没有则继续传递,如果都没有则由最后的接受者抛出异常或者是他来进行默认的处理。
何时使用
在处理消息的时候会过滤很多道条件。
如何解决
拦截的类都实现统一接口。
应用实例
- 红楼梦中的"击鼓传花"。
- JS 中的事件冒泡。
- JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。
- 员工请假时间
优点:
- 降低耦合度。它将请求的发送者和接收者解耦。
- 简化了对象。使得对象不需要知道链的结构。
- 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
- 更改添加判断逻辑方便。
缺点:
- 不能保证请求一定被接收。
- 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 大量的请求判断会导致系统性能的极具下降。【这个在文章最后会详细解释说明】
- 可能不容易观察运行时的特征,有碍于除错。
使用场景:
- 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
- 可动态指定一组对象处理请求。
示例于对比
通过是否使用了责任链的代码来直观感受一下之间的区别 。
代码业务逻辑
员工请假
这里的代码是一员工请假来实现的。
现在说一下员工请假的业务
员工请假会经过不同的上级批准:小于两天的假,经理有权限;小于五天的假,总监有权限批注;大于五天的假只有总监才有资格处理。
没有使用责任链
示例涉及到的类
- 创建请求实体 ApplyRequest
- 创建处理判断逻辑的类:Manager
- 测试:Test
没有使用责任链的代码
- 创建请求实体 ApplyRequest
/**
* @Description: 申请请求
* @Author: lick
* @CreateDate: 2019/11/16$ 22:22$
* @Version: 1.0
*/
public class ApplyRequest {
// 申请类型
private String requestType;
// 申请内容
private String requestContent;
// 申请数量
private int appNumber;
public String getRequestType() {
return requestType;
}
public void setRequestType(String requestType) {
this.requestType = requestType;
}
public String getRequestContent() {
return requestContent;
}
public void setRequestContent(String requestContent) {
this.requestContent = requestContent;
}
public int getAppNumber() {
return appNumber;
}
public void setAppNumber(int appNumber) {
this.appNumber = appNumber;
}
}
- 创建处理判断逻辑的类:Manager
/**
* @Description: 管理层
* @Author: lick
* @CreateDate: 2019/11/16$ 22:25$
* @Version: 1.0
*/
public class Manager {
protected String name;
// set 构造
public Manager(String name) {
this.name = name;
}
public void requestHandle(ApplyRequest applyRequest, String level){
if("经理".equals(level)){
if("请假".equals(applyRequest.getRequestType())
&& applyRequest.getAppNumber() <= 2){
System.out.println("请假数量小于等于2天,经理"+this.name+" 批准");
} else {
System.out.println("经理"+this.name+"无权处理");
}
} else if("总监".equals(level)){
if("请假".equals(applyRequest.getRequestType())
&& applyRequest.getAppNumber() <= 5){
System.out.println("请假数量小于等于=5天,总监"+this.name+" 批准");
} else {
System.out.println("总监"+this.name+"无权处理");
}
} else if("总经理".equals(level)){
if("请假".equals(applyRequest.getRequestType())){
System.out.println("请假被总经理"+this.name+"批准");
} else if("加薪".equals(applyRequest.getRequestType())){
if(applyRequest.getAppNumber() <= 300){
System.out.println("加薪"+applyRequest.getAppNumber()+",给总经理"
+this.name+"批准");
} else {
System.out.println("总经理"+this.name+"说要什么钱,要有梦想");
}
}
}
}
}
- 测试:Test
/**
* @Description: java类作用描述
* @Author: lick
* @CreateDate: 2019/11/16$ 22:36$
* @Version: 1.0
*/
public class Test {
public static void main(String[] args) {
Manager jingli = new Manager("Fame老师");
Manager zongjian = new Manager("ShineYork老师");
Manager zongjingli = new Manager("Pack老师");
ApplyRequest request = new ApplyRequest();
request.setRequestType("加薪");
request.setRequestContent("Zero老师请求加薪");
request.setAppNumber(200);
jingli.requestHandle(request, "经理");
zongjian.requestHandle(request, "总监");
zongjingli.requestHandle(request, "总经理");
}
}
从上面可以看出,Manager 中的代码十分臃肿,这么简单的逻辑全在一个类中,一个方法中。如果逻辑更加复杂那岂不是一个方法几百上千上万行的代码。如果不同的判断涉及到不同的private变量,那岂不是可读性又变得更加低了,就算是抽成同类不同的方法也会感觉十分的臃肿。这样的代码是十分的不易修改和阅读,当需求变化时你可能会需要一杯红牛陪伴加班。。。。
使用责任链的代码
下面看看责任链的处理:
涉及到的类
- 请求实体:ApplyRequest
- 创建父类:ManagnSixsta
- 将不同的经理职位对象化【记住万物皆对象】,创建管理层的类:CommonManager,GeneraManager,MajordomoManager
- 测试:ChainTest
代码如下
- 请求实体:ApplyRequest
/**
* @Description: 申请请求
* @Author: lick
* @CreateDate: 2019/11/16$ 22:22$
* @Version: 1.0
*/
public class ApplyRequest {
// 申请类型
private String requestType;
// 申请内容
private String requestContent;
// 申请数量
private int appNumber;
public String getRequestType() {
return requestType;
}
public void setRequestType(String requestType) {
this.requestType = requestType;
}
public String getRequestContent() {
return requestContent;
}
public void setRequestContent(String requestContent) {
this.requestContent = requestContent;
}
public int getAppNumber() {
return appNumber;
}
public void setAppNumber(int appNumber) {
this.appNumber = appNumber;
}
}
- 创建父类:ManagnSixstar
/**
* @Description: 管理层抽象类
* @Author: lick
* @CreateDate: 2019/11/16$ 22:49$
* @Version: 1.0
*/
public abstract class ManagnSixstar {
// 管理者名字
protected String name;
// 上级领导 null 总经理
protected ManagnSixstar superior;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ManagnSixstar getSuperior() {
return superior;
}
public void setSuperior(ManagnSixstar superior) {
this.superior = superior;
}
/**
* 请求处理接口
* @param applyRequest
*/
public abstract void applyRequestHandle(ApplyRequest applyRequest);
}
- 将不同的经理职位对象化【记住万物皆对象】,创建管理层的类:CommonManager,GeneraManager,MajordomoManager
/**
* @Description: 管理层 -- 经理
* @Author: lick
* @CreateDate: 2019/11/16$ 22:55$
* @Version: 1.0
*/
public class CommonManager extends ManagnSixstar{
public void applyRequestHandle(ApplyRequest applyRequest) {
if("请假".equals(applyRequest.getRequestType())
&& applyRequest.getAppNumber() <= 2){
System.out.println("请假数量小于等于2天,经理"+this.name+" 批准");
} else {
// System.out.println("经理"+this.name+"无权处理");
if(superior != null){
superior.applyRequestHandle(applyRequest);
}
}
}
}
/**
* @Description: 管理层 -- 总经理
* @Author: lick
* @CreateDate: 2019/11/16$ 23:00$
* @Version: 1.0
*/
public class GeneraManager extends ManagnSixstar{
public void applyRequestHandle(ApplyRequest applyRequest) {
if("请假".equals(applyRequest.getRequestType())){
System.out.println("请假被总经理"+this.name+"批准");
} else if("加薪".equals(applyRequest.getRequestType())){
if(applyRequest.getAppNumber() <= 300){
System.out.println("加薪"+applyRequest.getAppNumber()+",给总经理"
+this.name+"批准");
} else {
System.out.println("总经理"+this.name+"说要什么钱,要有梦想");
}
}
}
}
/**
* @Description: 管理层 -- 总监
* @Author: lick
* @CreateDate: 2019/11/16$ 22:58$
* @Version: 1.0
*/
public class MajordomoManager extends ManagnSixstar{
public void applyRequestHandle(ApplyRequest applyRequest) {
if("请假".equals(applyRequest.getRequestType())
&& applyRequest.getAppNumber() <= 5){
System.out.println("请假数量小于等于=5天,总监"+this.name+" 批准");
} else {
// System.out.println("总监"+this.name+"无权处理");
if(superior != null){
superior.applyRequestHandle(applyRequest);
}
}
}
}
- 测试:ChainTest
/**
* @Description: java类作用描述
* @Author: lick
* @CreateDate: 2019/11/16$ 23:02$
* @Version: 1.0
*/
public class ChainTest {
public static void main(String[] args) {
CommonManager jingli = new CommonManager();
MajordomoManager zongjian = new MajordomoManager();
GeneraManager zongjingli = new GeneraManager();
// 设置你是谁
jingli.setName("Fame老师");
// 设置上层领导是谁
jingli.setSuperior(zongjian);
// 设置你是谁
zongjian.setName("ShineYork老师");
// 设置上层领导是谁
zongjian.setSuperior(zongjingli);
// 设置你是谁
zongjingli.setName("Pack老师");
// 设置上层领导是谁
zongjingli.setSuperior(zongjingli);
ApplyRequest request = new ApplyRequest();
request.setRequestType("加薪");
request.setRequestContent("Zero老师请假加薪");
request.setAppNumber(200);
// 重点
jingli.applyRequestHandle(request);
System.out.println("=======================================");
System.out.println("=======================================");
System.out.println("=======================================");
ApplyRequest request2 = new ApplyRequest();
request2.setRequestType("请假");
request2.setRequestContent("Zero老师请假");
request2.setAppNumber(6);
jingli.applyRequestHandle(request2);
}
}
上面的代码是责任链的代码,虽然代码变多了但是这种代码确实有很高的可读性,可改性(解耦)。
但是也存在一个缺点:虽然可读性的提升了,但是某些情况下会导致程序性能的消耗。假如责任链比较长,而且每次都是最后的接受对象来处理这个事件消息,大量的这种情况会导致程序性能严重降低,比如双十一的时候用户请求极具上升就会导致这个问题。
由此可得不是所有的情况都要是用责任链模式。设计模式的初衷是优化代码优化程序,当他不能在你需要的情况下的到提升是可以不是用设计模式的。不是所有的情况都要使用设计模式,我们更多的需要思考是否有用