行为模式:职责链模式
简介
责任链模式:为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
举个例子,小明因为感冒需要请假,此时它的需要请3天,但是他的小组长只有1天的允许权限,小组长的领导项目经理有2天的权限,而能允许3天的只有老板,但是小明是新员工,所以它只能一步步的问,直到问到老板才成功请到了假期。
但是如果小明的公司更大,那么它的审批流程就可能会更加复杂,如果人事流通了,说不定还得重新问一遍,有没有什么办法能方便一点呢?
于是就有了职责链模式,它可以理解为一个申请表单,只要有领导在职责链上,那么表单就会通过层层传递,直到有领导处理这个事情,其他没有权限处理的只需要自动抛给上级就行了,小明就不需要一个个问了。
那么每次请假只需要提交一个申请表单即可。
这个链和链表的结构差不多,每个领导会持有它上级的引用,以便在自己无权限时抛给上级来处理。
这其实会有一个问题,比如小明想当老板,这个请求被一层层传递,就算到老板那,老板也没权利处理啊,是啊,所以职责链模式不能保证每个请求一定被处理,所以我们最好加上报错或者警告提示之类的提示。
为此这个模式有三个角色:
- 抽象处理者:定义一个处理请求的接口,以及下一个处理者的引用
- 具体的处理者:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。客户类可以看成是实际使用时的封装,它会创建处理链,并将需要处理的请求交给第一个链式对象。
代码实现
//抽象处理者
abstract class Handler {
protected allowDay: number; //允许请假的天数
protected nextHandler: Handler | null = null;
constructor(allowDay: number) {
this.allowDay = allowDay;
}
//是否在允许的范围内
protected isAllowed(day: number): boolean {
return this.allowDay >= day;
}
//设置下一个处理者
public setNextHandler(handler: Handler) {
this.nextHandler = handler;
}
//处理请求的接口
public askLeave(day: number): boolean {
if (this.isAllowed(day)) {
return true;
} else {
if (!this.nextHandler) {
console.log(`我已经是最后一个处理者了,请假${day}天,不允许`);
return false;
} else {
return this.nextHandler.askLeave(day);
}
}
}
}
//小组长
class Heads extends Handler {
constructor(allowDay: number) {
super(allowDay);
}
}
//小组长
class ProjectManager extends Handler {
constructor(allowDay: number) {
super(allowDay);
}
}
//老板
class Boss extends Handler {
constructor(allowDay: number) {
super(allowDay);
}
}
//客户类
class Client {
constructor() {
//创建处理者实例
const heads = new Heads(1);
const projectManager = new ProjectManager(2);
const boss = new Boss(3);
//创建链表
heads.setNextHandler(projectManager);
projectManager.setNextHandler(boss);
//请假
const status = heads.askLeave(2);
if (status) {
console.log(`请假2天成功`);
} else {
console.log(`请假2天失败`);
}
//请假2
const status2 = heads.askLeave(4);
if (status2) {
console.log(`请假4天成功`);
} else {
console.log(`请假4天失败`);
}
}
}
new Client();
由于例子的业务逻辑很简单,所以我把具体的请求处理askLeave
写在基类里面了,省的后面每个子类都写一样的代码。
如果业务复杂,这个处理肯定只能作为一个抽象方法交个子类去具体实现的。
应用场景
- 多个对象可以处理一个请求,但具体由哪个对象处理该请求在运行时自动确定。
- 可动态指定一组对象处理请求,或添加新的处理者。
- 需要在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。
扩展
- 纯的职责链模式:一个请求必须被某一个处理者对象所接收,且一个具体处理者对某个请求的处理只能采用以下两种行为之一:自己处理(承担责任);把责任推给下家处理。
- 不纯的职责链模式:允许出现某一个具体处理者对象在承担了请求的一部分责任后又将剩余的责任传给下家的情况,且一个请求可以最终不被任何接收端对象所接收。
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据