职责链模式
职责链是一种典型的 行为 型设计模式,核心在于链。
比方
- 一公司有 3 个程序员
小A
、小B
、小C
- 一天产品经理有一个新需求,他不清楚这需求由谁来负责
- 于是找到小 A。
- 小 A 说这事不归我管,你问问小 B 吧
- 产品经理又找到了小 B
- 小 B 说这一块也不归我,你问问小 C
- 小 C 接下了这个需求
一个任务从 A 转到 B,从 B 转到 C,再由 C 最终处理,形成了一个完整的任务处理链条
面对一个新任务,每个任务处理者需要判断自己能否处理该任务,如果能处理,则处理并返回;如果不能处理,则转交给下一个任务处理者,直到某一个处理者最终完成处理
。这就是职责链模式核心思想
在职责链模式中,小 A 小 B 小 C 这样的任务处理者被称为 Handler
产品经理的角色则是 Client 的角色
应用场景
- 职责链有些像数据结构中的链表
- 职责链可以对每个任务进行部分处理,直到最后才吧任务处理完毕
- 若干个过滤器组成一个职责链,每一个过滤器过滤一部分非法内容
UML
实现
每一个具体 Handler 类都继承自统一的抽象类
- Handle 对象包含一个 successor 成员,指向它的下一个任务处理者(链表节点的 next 指针)
abstract public class Handler {
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
abstract String handleRequest(String msg);
}
实现三个具体的 Handler 类,用于替换吧某一个字符替换成*
public class HandlerA extends Handler {
@Override
String handleRequest(String msg) {
if(msg.contains("a")){
msg = msg.replace('a', '*');
} else if(this.successor != null){
msg = this.successor.handleRequest(msg);
}
return msg;
}
}
public class HandlerB extends Handler {
@Override
String handleRequest(String msg) {
if(msg.contains("b")){
msg = msg.replace('b', '*');
} else if(this.successor != null){
msg = this.successor.handleRequest(msg);
}
return msg;
}
}
public class HandlerC extends Handler {
@Override
String handleRequest(String msg) {
if(msg.contains("c")){
msg = msg.replace('c', '*');
} else if(this.successor != null){
msg = this.successor.handleRequest(msg);
}
return msg;
}
}
public class Client {
public static void main(String[] args) {
Handler handlerA = new HandlerA();
Handler handlerB = new HandlerB();
Handler handlerC = new HandlerC();
handlerA.setSuccessor(handlerB);
handlerB.setSuccessor(handlerC);
System.out.println(handlerA.handleRequest("apple"));
System.out.println(handlerA.handleRequest("bicycle"));
System.out.println(handlerA.handleRequest("color"));
}
}
职责链的缺点
- Debug 不友好,链路深的时候需压调试很多层
框架中的应用
- Tomcat 容器中的过滤器 Filter
- 过滤器针对请求的访问、参数合法性等方面进行验证和过滤
- SpringMVC 中的拦截器
- 客户端 HTTP 请求到了 Web 应用之后,会被 SpringMVC 框架中的 DisapatcherServlet 类进行分发给 Controller 层具体方法
- 在进入 Controller 层业务逻辑之前、以及执行完逻辑之后都会经过一系列的拦截器 Interceptor
Javascript 职责链
var order01 = function () {
console.log(1);
return "nextSuccessor";
};
var order02 = function () {
console.log(2);
var self = this;
setTimeout(function () {
self.next();
}, 1000);
};
var order03 = function () {
console.log(3);
};
var Chain = function (fn) {
this.fn = fn;
this.successor = null;
};
Chain.prototype.setNextSuccessor = function (successor) {
//指定在链中的下一个节点
return (this.successor = successor);
};
Chain.prototype.passRequest = function () {
//传递请求给某个节点
var ret = this.fn.apply(this, arguments);
if (ret === "nextSuccessor") {
return (
this.successor &&
this.successor.passRequest.apply(this.successor, arguments)
);
}
return ret;
};
Chain.prototype.next = function () {
return (
this.successor &&
this.successor.passRequest.apply(this.successor, arguments)
);
};
// 现在我们把 3个订单函数分别包装成职责链的节点:
var fn1 = new Chain(order01);
var fn2 = new Chain(order02);
var fn3 = new Chain(order03);
// 然后指定节点在职责链中的顺序:
fn1.setNextSuccessor(fn2).setNextSuccessor(fn3);
// 最后把请求传递给第一个节点:
fn1.passRequest();
参见