设计模式-责任链模式
一、定义
又叫职责链模式,它是一种对象行为模式,旨在避免发送请求者与多个处理请求者耦合在一起,它将所有请求的处理者通过前一对象记住其下一对象的引用而形成一条链;当有请求时,可将请求沿着这条链进行传递,直到有对象处理请求为止。
二、优点
1、降低了对象之间的耦合度,发送者无需知道具体由哪些对象处理其请求以及处理链的结构,发送者和接受者也无需拥有对方的明确信息。
2、增强了系统的可扩展性,可根据需求增加新的处理类,满足开闭原则。
3、增强了给对象指派职责的灵活性。当处理流程发生变化时,可以动态地改变链条内的成员或调动他们的顺序,也可以动态地增加或者删除责任。
4、责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,无需保持其他所有处理者的引用,这避免了使用众多的 ( if ) 或者 ( if...else ) 语句。
5、处理者分工明确。每个处理者只需处理自己该处理的工作,不该处理的传递给下一个处理者完成;各个处理类明确自己的 责任范围,符合职责单一原则。
三、缺点
1、无法保证每个请求一定被处理。由于一个请求没有明确的接受者,因此无法保证该请求一定会被处理,即便一直传到链的末端也得不到处理。
2、对于比较长的职责链,会涉及到比较多的处理对象,系统性可能会受到一定影响。
3、职责链建立的合理性需要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,比如可能会造成循环调用。
四、模式结构与实现
1)模式的结构
抽象处理者(Handler):处理请求的接口,它定义了一个处理的抽象方法和一个后继连接。
具体处理者(Concrete Handler):继承或实现抽象处理者。具体实现抽象处理者的处理方法,判断能否处理本次请求,可以则处理,不可以则将请求转给它的后继者。
客户类:创建处理链接,并向链头的具体处理者提交请求,它并不关心处理的细节及请求在链上的传递过程。
结构图:
客户端可按下图设置责任链:
责任链.png
2)模式的实现
//客户端请求类
public class ChainOfResponsibilityPattern {
public static void main(String[] args) {
//组装责任链
Handler handler1=new ConcreteHandler1();
Handler handler2=new ConcreteHandler2();
handler1.setNext(handler2);
//提交请求
handler1.handleRequest("two");
}
}
//抽象处理者角色
abstract class Handler {
private Handler next;
public void setNext(Handler next) {
this.next=next;
}
public Handler getNext() {
return next;
}
//处理请求的方法
public abstract void handleRequest(String request);
}
//具体处理者角色1
class ConcreteHandler1 extends Handler {
public void handleRequest(String request) {
if(request.equals("one")) {
System.out.println("具体处理者1负责处理该请求!");
} else {
if(getNext() != null) {
getNext().handleRequest(request);
} else {
System.out.println("没有人处理该请求!");
}
}
}
}
//具体处理者角色2
class ConcreteHandler2 extends Handler {
public void handleRequest(String request) {
if(request.equals("two")) {
System.out.println("具体处理者2负责处理该请求!");
} else {
if(getNext() != null) {
getNext().handleRequest(request);
} else {
System.out.println("没有人处理该请求!");
}
}
}
}
运行结果:
具体处理者2负责处理该请求!
五、应用场景
责任链模式通常在以下几种情况使用:
1、有多个对象可以处理一个请求,哪个对象处理该请求由运行时刻自动确定。
2、可动态指定一组对象处理请求,或添加新的处理者。
3、在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。
六、应用实例
1)需求
用责任链模式设计一个请假条审批模块。
2)分析
规定学生请假小于或等于 2 天,班主任可以批准;小于或等于 7 天,系主任可以批准;小于或等于 10 天,院长可以批准;其他情况不予批准;这个实例适合使用职责链模式实现。
3)设计思路
1、抽象处理类
定义一个领导类(Leader),它是抽象处理者,包含了一个指向下一位领导的指针 next 和一个处理假条的抽象处理方法 handleRequest(int LeaveDays);
2、具体处理类
定义班主任类(ClassAdviser)、系主任类(DepartmentHead)和院长类(Dean),它们是抽象处理者的子类,是具体处理者,必须根据自己的权力去实现父类的 handleRequest(int LeaveDays) 方法,如果无权处理就将假条交给下一位具体处理者。
3、客户类
负责创建处理链,并将假条交给链头的具体处理者(班主任)。
4、结构图
4)程序实现
public class LeaveApprovalTest {
public static void main(String[] args) {
//组装责任链
Leader teacher1=new ClassAdviser();
Leader teacher2=new DepartmentHead();
Leader teacher3=new Dean();
//Leader teacher4=new DeanOfStudies();
teacher1.setNext(teacher2);
teacher2.setNext(teacher3);
//teacher3.setNext(teacher4);
//提交请求
teacher1.handleRequest(8);
}
}
//抽象处理者:领导类
abstract class Leader {
private Leader next;
public void setNext(Leader next) {
this.next=next;
}
public Leader getNext() {
return next;
}
//处理请求的方法
public abstract void handleRequest(int LeaveDays);
}
//具体处理者1:班主任类
class ClassAdviser extends Leader {
public void handleRequest(int LeaveDays) {
if(LeaveDays <= 2) {
System.out.println("班主任批准您请假" + LeaveDays + "天。");
} else {
if(getNext() != null) {
getNext().handleRequest(LeaveDays);
} else {
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
//具体处理者2:系主任类
class DepartmentHead extends Leader {
public void handleRequest(int LeaveDays) {
if(LeaveDays <= 7) {
System.out.println("系主任批准您请假" + LeaveDays + "天。");
} else {
if(getNext() != null) {
getNext().handleRequest(LeaveDays);
} else {
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
//具体处理者3:院长类
class Dean extends Leader {
public void handleRequest(int LeaveDays) {
if(LeaveDays <= 10) {
System.out.println("院长批准您请假" + LeaveDays + "天。");
} else {
if(getNext() != null) {
getNext().handleRequest(LeaveDays);
} else {
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
//具体处理者4:教务处长类
class DeanOfStudies extends Leader {
public void handleRequest(int LeaveDays) {
if(LeaveDays <= 20) {
System.out.println("教务处长批准您请假"+LeaveDays+"天。");
} else {
if(getNext()!=null) {
getNext().handleRequest(LeaveDays);
} else {
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
程序运行结果如下:
院长批准您请假8天。
5)扩展
假如增加一个教务处长类,可以批准学生请假 20 天,也非常简单,代码如下:
//具体处理者4:教务处长类
class DeanOfStudies extends Leader {
public void handleRequest(int LeaveDays) {
if(LeaveDays<=20) {
System.out.println("教务处长批准您请假"+LeaveDays+"天。");
} else {
if(getNext()!=null) {
getNext().handleRequest(LeaveDays);
} else {
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
七、责任链模式在开源项目中的应用
1)Spring MVC
在springMVC中,DispatcherServlet这个核心类中使用到了HandlerExecutionChain这个类,他就是责任链模式实行的具体类。
2)Servlet过滤器
request,response参数通过两个过滤器 HTMLFilter SesitiveFilter 过滤掉一些非法内容。