责任链模式(Chain of Responsibility Pattern)
责任链模式是一种行为模式,在责任链模式中,很多对象由每一个对象对其下家的引用而连接起来形成一条链。客户端应用在这个链上进行传递,直到链上的某一个对象决定处理此请求。发出请求的客户并不知道链上的哪一个对象最终处理这个请求。这使系统可以不影响客户端的情况下动态地重新组织和分配责任。
责任链模式涉及的角色如下:
1. 抽象处理者角色(Handler):定义出一个处理请求的接口。如果需要,接口可以定义出一个方法,以设定和返回下家的引用。
2. 具体处理者角色(ConcreteHandler):具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于处理者持有下家引用,因此,如果需要,具体处理者可以访问下家。
介绍
意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
应用场景:
1. 有多个对象处理同一个请求,具体由哪一个来处理还不确定,只有在运行时才能确定哪个对象处理的情况。
2. 消息有多个接收者,而接收对象又是不明确的情况。只需要向其中一个对象发出消息,由其内部具体处理。
3. 同一个消息的多个处理对象可能会动态地增加或者减少,需要动态地指定的情况。
优点:1. 降低耦合度。它将请求的发送者和接收者解耦。2. 简化了对象。使得对象不需要知道链的结构。3. 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4. 增加新的请求处理类很方便。
缺点:1. 不能保证请求一定被接收。2. 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。3. 可能不容易观察运行时的特征,有碍于除错。
注意事项:在JAVA WEB中遇到很多应用。
实现
关于实现过程中,我们模拟一个学生请假的过程,学生请假,如果学生请假时间比较短,可以直接跟班长汇报一声即可,如果时间较长可以找班主任审批,如果时间过长,则需要汇报校长进行审批。在该模式中,抽象出来的逻辑即是学生请假(请求),(班长,老师,校长)处理者进行处理。在此抽象中,班长,老师,校长可作为一个责任链(处理学生请假请求)。
步骤 1
我们构造一个学生接口,该接口定义学生的行为。
IStudent.java
package com.study.ResponsibilityPattern;
/**
* 学生接口
* @author admin
*
*/
public interface IStudent {
/**
* 获取学生生病状态(用数字0,1,2模拟)
* 0:学生生病状态轻微,班长可以直接处理
* 1:学生生病状态一般,需要老师处理
* 2:学生生病状态严重,需要校长处理
* @return
*/
public int getState();
/**
* 获得学生病假处理情况
* @return
*/
public String getRequestMessage();
}
构造一个处理者接口。用来处理学生的请假请求。
IHandler.java
package com.study.ResponsibilityPattern;
/**
* 处理者接口
* @author admin
*
*/
public interface IHandler {
/**
* 处理学生请假
* @param student
*/
public void handleRequest(IStudent student);
/**
* 设置下一级流程处理者
* @param handler
*/
public void setHandler(IHandler handler);
}
定义一个抽象类,实现了处理者接口。抽象类中包含了一个下一级处理者的引用,同时定义了一个当前处理者可以处理的学生请假请求的生病状态。
AbstractHandler.java
package com.study.ResponsibilityPattern;
/**
* 抽象处理类
* @author admin
*/
public abstract class AbstractHandler implements IHandler{
private int state;
private IHandler handler;
public AbstractHandler(int state) {
this.state = state;
}
public abstract void process(IStudent student);
public void handleRequest(IStudent student) {
if(student != null) {
if(student.getState() == getState()) {
this.process(student);
}else {
if(this.handler != null) {
this.handler.handleRequest(student);
}
}
}
}
public int getState() {
return state;
}
public void setHandler(IHandler handler) {
this.handler = handler;
}
}
步骤 2
实现学生接口。学生实体类中有一个描述学生目前生病状态的关键字,state。
Student.java
package com.study.ResponsibilityPattern;
public class Student implements IStudent{
private int state;
public Student(int state) {
this.state = state;
}
public int getState() {
return this.state;
}
public String getRequestMessage() {
return "可以请假";
}
}
构造班长,教师,校长,三个具体的请求处理者。
班长
SquadLeaderHandler.java
package com.study.ResponsibilityPattern;
/**
* 班长处理
* @author admin
*
*/
public class SquadLeaderHandler extends AbstractHandler{
public SquadLeaderHandler() {
super(0);
}
@Override
public void process(IStudent student) {
System.out.println("班长处理:" + student.getRequestMessage());
}
}
教师
TeacherHandler.java
package com.study.ResponsibilityPattern;
/**
* 老师处理者
* @author admin
*
*/
public class TeacherHandler extends AbstractHandler{
public TeacherHandler() {
super(1);
}
@Override
public void process(IStudent student) {
System.out.println("老师批复:" + student.getRequestMessage());
}
}
校长
SchoolMasterHandler.java
package com.study.ResponsibilityPattern;
public class SchoolMasterHandler extends AbstractHandler{
public SchoolMasterHandler() {
super(2);
}
@Override
public void process(IStudent student) {
System.out.println("校长批复:" + student.getRequestMessage());
}
}
步骤 3
在步骤3这个地方,我们要实现一个学生请假请求过来的时候,真正的处理流程。我们借鉴了外观模式的思想,构造了一个统一的处理请求的类,以此屏蔽学生请假请求的具体处理。
ProcessHandler.java
package com.study.ResponsibilityPattern;
/**
* 这个类的出现主要的目的就是采用设计模式的另外一种思想(外观模式)
* <直接对外提供一个接口,屏蔽系统内部处理>
* @author admin
*/
public class ProcessHandler {
private final IHandler squadLeaderHandler;
private final IHandler teacherHandler;
private final IHandler schoolMasterHandler;
public ProcessHandler() {
schoolMasterHandler = new SchoolMasterHandler();
teacherHandler = new TeacherHandler();
squadLeaderHandler = new SquadLeaderHandler();
this.squadLeaderHandler.setHandler(this.teacherHandler);
this.teacherHandler.setHandler(this.schoolMasterHandler);
}
private static ProcessHandler test = new ProcessHandler();
public static ProcessHandler getInstance() {
if(null != test) {
return test;
}else {
test = new ProcessHandler();
return test;
}
}
/**
* 处理消息
* @param student
*/
public void onMessage(IStudent student) {
//交给第一级处理者进行处理(班长)
this.squadLeaderHandler.handleRequest(student);
}
}
步骤 4
测试类的构造。
Test.java
package com.study.ResponsibilityPattern;
import java.util.Random;
/**
* 测试
* @author admin
*
*/
public class Test {
public static void main(String[] args) {
ProcessHandler handler = ProcessHandler.getInstance();
for(int i = 0; i < 5; i ++) {
//随机生成0-3之间的随机数(0,1,2)
int state = new Random().nextInt(3);
//构造学生对象
IStudent student = new Student(state);
//使用外观模式进行处理
handler.onMessage(student);
}
}
}
验证输出。结果具有随机性,读者自行验证。
校长批复:可以请假
班长处理:可以请假
班长处理:可以请假
老师批复:可以请假
校长批复:可以请假