将多个对象连成一条链,并沿这条链传递请求,直到有对象处理它为止
就如同请假一样,你请假给你的直系领导,但是直系领导没有权利批假,他又会向他的领导提申请一样。一重一重的往上传递,直到有人能处理,在一重一重的回调回来。用代码来解释:
定义一个领导的接口:
public interface ILeader {
/**
* 请假结果
*
* @return 返回请假结果
*/
String result(int date);
}
定义链,即上一级领导:
public interface ILeave {
/**
* 设置领导
*
* @param nextLeader 领导
*/
void nextLeader(ILeader nextLeader);
}
抽象一个领导,封装公用方法:
public abstract class Leave implements ILeave, ILeader {
//持有上级领导的引用
protected ILeader leader;
@Override
public void nextLeader(ILeader nextLeader) {
this.leader = nextLeader;
}
}
具体一个领导:
//组长
public class TeamLeader extends Leave {
//自己可以批的假的天数
private final int batchLeaveDate = 2;
@Override
public String result(int date) {
if (batchLeaveDate >= date) {
//自己可以批这个假
return "TeamLeader:请假批准";
}
//自己不可以批这个假,并且他有上级领导
if (leader != null) {
return leader.result(date);
}
return "TeamLeader:没人能批假";
}
}
定义一个普通员工:
public class Staff extends Leave {
@Override
public String result(int date) {
//向上级请假,得到请假结果
return leader.result(date);
}
}
再多定义几个领导:
//经理
public class Manager extends Leave {
//自己可以批的假的天数
private final int batchLeaveDate = 4;
@Override
public String result(int date) {
if (batchLeaveDate >= date) {
//自己可以批这个假
return "Manager:请假批准";
}
if (leader != null) {
return leader.result(date);
}
return "Manager:没人能批假";
}
}
//总经理
public class GeneralManager extends Leave {
//自己可以批的假的天数
private final int batchLeaveDate = 10;
@Override
public String result(int date) {
if (batchLeaveDate >= date) {
//自己可以批这个假
return "GeneralManager:请假批准";
}
if (leader != null) {
return leader.result(date);
}
return "GeneralManager:没人能批假";
}
}
//老板
public class Boss extends Leave {
//自己可以批的假的天数
private final int batchLeaveDate = 30;
@Override
public String result(int date) {
if (batchLeaveDate >= date) {
//自己可以批这个假
return "Boss:请假批准";
}
if (leader != null) {
return leader.result(date);
}
return "Boss:走人吧,没有这么长的假";
}
}
在客户端中使用:
public class Client {
public static void main(String[] args) {
//创建各个领导对象,即多个对象
Boss boss = new Boss();
GeneralManager generalManager = new GeneralManager();
Manager manager = new Manager();
TeamLeader teamLeader = new TeamLeader();
//设置各个领导的上级领导,即构成一条链
teamLeader.nextLeader(manager);
manager.nextLeader(generalManager);
generalManager.nextLeader(boss);
//创建员工对象
Staff staff = new Staff();
//设置员工对象的领导
staff.nextLeader(teamLeader);
//请假一天,得到结果
String result = staff.result(1);
System.out.println(result);
}
}
到这里,责任链模式就完成,还有一种写法,就是Okhttp的拦截器,需要多一个辅助类,下面仿照okhttp的责任链,重新定义 ILeader 接口:
public interface ILeader {
//得到结果
String result(Chain chain);
//定义一个链的接口
interface Chain {
//定义需要传递的参数,即请假天数
int leaveDate();
//得到结果
String proceed(int date);
}
}
增加一个辅助类:
//实现ILeader.Chain接口
public class Company implements ILeader.Chain {
private List<ILeader> leaders;
private int index, leaveDate;
//构造方法传递所有的领导列表,当前的领导下标,需要传递的参数
public Company(List<ILeader> leaders, int leaveDate, int index) {
this.leaders = leaders;
this.index = index;
this.leaveDate = leaveDate;
}
@Override
public int leaveDate() {
//返回需要传递的参数
return leaveDate;
}
@Override
public String proceed(int date) {
//在 proceed 方法中从新创建一个Company对象,注意 index 下标加 1
//代表了下一个领导
Company next = new Company(leaders, date, index + 1);
//根据下标,获取领导
ILeader leader = leaders.get(index);
//调用领导的处理方法,处理这个请假
return leader.result(next);
}
}
重新编写领导:
//实现ILeader 接口
public class TeamLeader implements ILeader {
//自己可以批的假的天数
private final int batchLeaveDate = 2;
@Override
public String result(Chain chain) {
//通过辅助类,获取传递的参数,即请假天数
int leaveDate = chain.leaveDate();
//判断自己是否可以批假
if (batchLeaveDate >= leaveDate) {
return "TeamLeader:批假了";
}
//不可以,通过辅助类来走下一个领导
return chain.proceed(chain.leaveDate());
}
}
再来一个领导
public class Boss implements ILeader {
//自己可以批的假的天数
private final int batchLeaveDate = 30;
@Override
public String result(Chain chain) {
int leaveDate = chain.leaveDate();
if (batchLeaveDate >= leaveDate) {
return "Boss:批假了";
}
return "走人吧";
}
}
在 Client 中使用:
public class Client {
public static void main(String[] args) {
//定义领导列表
List<ILeader> leaders = new ArrayList<>();
//往列表中新添加领导,注意,先添加会先经过
//因为是通过index下表来获取的
leaders.add(new TeamLeader());
leaders.add(new Boss());
//创建辅助类Company,注意,index 初始值为0,需要传递的参数和下面一致即可
Company company = new Company(leaders, 35, 0);
//调用请假,获取请假结果
String result = company.proceed(35);
System.out.println(result);
}
}
上面这种就是仿照okhttp的拦截器写的责任链,相比上一种,就不需要逐个对象设置链。注意,使用这种写法一定有一个是返回结果的,即总会有一个终结点,否则会出现数组下标越界的错误。
网友评论