一、定义
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
责任链模式涉及到的角色如下所示:
1>抽象处理者角色(Handler):定义出一个处理请求的接口。如果需要,接口可以定义出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。
2>具体处理者角色(ConcreteHandler):具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
二、适用场景
1>有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
2>在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
3>可动态指定一组对象处理请求。
三、实现
以请假流程为例(转于https://www.cnblogs.com/fengyumeng/p/10839570.html),3天以下的假小组长签字即可,3-7天的假需要小组长和部门经理签字,7以上的假小组长和部门经理签完字后还需要总经理签字。
角色1:请假条,其实可以理解成请假人,因为请假条上自然有请假人信息。
角色2:领导人,小组长、部门经理、总经理都是审批人。
动作:领导人审批请假条。
请假条:
public class Leave {
private String name;//姓名
private int num;//请假天数
private String content;//请假内容
public Leave(String name, int num, String content) {
this.name = name;
this.num = num;
this.content = content;
}
public String getName() {
return name;
}
public int getNum() {
return num;
}
public String getContent() {
return content;
}
}
处理者抽象:
public abstract class Handler {
protected final static int NUM_ONE = 1;
protected final static int NUM_THREE = 3;
protected final static int NUM_SEVEN = 7;
//该领导处理的请假天数区间
private int numStart = 0;
private int numEnd = 0;
//领导上面还有领导
private Handler nextHandler;
//设置请假天数范围 上不封顶
public Handler(int numStart) {
this.numStart = numStart;
}
//设置请假天数范围
public Handler(int numStart, int numEnd) {
this.numStart = numStart;
this.numEnd = numEnd;
}
//设置上级领导
public void setNextHandler(Handler nextHandler){
this.nextHandler = nextHandler;
}
//提交请假条
public final void submit(Leave leave){
if(0 == this.numStart){
return;
}
//如果请假天数达到该领导者的处理要求
if(leave.getNum() >= this.numStart){
this.handleLeave(leave);
//如果还有上级 并且请假天数超过了当前领导的处理范围
if(null != this.nextHandler && leave.getNum() > numEnd){
this.nextHandler.submit(leave);//继续提交
}
}
}
//各级领导处理请假条方法
protected abstract void handleLeave(ILeave leave);
}
小组长:
public class GroupLeader extends Handler {
public GroupLeader() {
//小组长处理1-3天的请假
super(Handler.NUM_ONE, Handler.NUM_THREE);
}
@Override
protected void handleLeave(ILeave leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("小组长审批:同意。");
}
}
部门经理:
public class Manager extends Handler {
public Manager() {
//部门经理处理3-7天的请假
super(Handler.NUM_THREE, Handler.NUM_SEVEN);
}
@Override
protected void handleLeave(ILeave leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("部门经理审批:同意。");
}
}
总经理:
public class BigManager extends Handler {
public BigManager() {
//部门经理处理7天以上的请假
super(Handler.NUM_SEVEN);
}
@Override
protected void handleLeave(ILeave leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("总经理审批:同意。");
}
}
客户端:
public static void main(String[] args) {
//请假条来一张
Leave leave = new Leave("小花",5,"身体不适");
//各位领导
Handler groupLeader = new GroupLeader();
Handler manager = new Manager();
Handler bigManager = new BigManager();
groupLeader.setNextHandler(manager);//小组长的领导是部门经理
manager.setNextHandler(bigManager);//部门经理的领导是总经理
//之所以在这里设置上级领导,是因为可以根据实际需求来更改设置,如果实战中上级领导人都是固定的,则可以移到领导实现类中。
//提交申请
groupLeader.submit(leave);
}
四、优缺点
优点: 1>降低耦合度。它将请求的发送者和接收者解耦。 请求的发送者不用关心具体是谁去解决问题;
2>简化了对象。使得对象不需要知道链的结构;
3>增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任;
4>增加新的请求处理类很方便。
缺点: 1>不能保证请求一定被接收;
2>系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用;
3>可能不容易观察运行时的特征,有碍于除错。