这是我参与8月更文挑战的第 30 天,活动详情查看:8月更文挑战
定义
为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
杂谈
职责链模式其实和我们日常使用的单向链表结构非常的相似,每个节点头尾相连,当我们需要匹配某一个节点时,需要重头遍历到末端,如下就是单向链表的示意图
如果不套用设计模式,在代码里的结构,会是类似与 if...else if...else if 的同级并列结构,如果需要调整 else if 中的条件顺序,只有硬编码才能处理
代码示例 v1
父类
先定义一个抽象父类,他里面有一个next 的实例会指向下一个自己的继承类。这个抽象类中,又定义了一个处理的方法 request(),我们的子类对这个 request() 实现,需要判断能否在当前类中完成工作,如果无法完成,就转交给他的next,通过next. request() 将这个处理请求往后传递
abstract class Handler {
private Handler next;
public abstract void request();
public Handler setNext(Handler next){
this.next = next;
return next;
}
}
子类
我们编写一个子类的代码模版,当子类通过条件判断后发现自己无法处理后,直接甩锅给下一个
class Handler1 extends Handler {
public void request(){
if(...){
next.request();
}else{
// 处理
}
}
}
下图是这个设计模式的 UML
client 调用
我们需要提前组装好他们的处理顺序,然后让客户端直接调用头节点(或者说是这一串处理环节的一个 Hander 子类)的 request()
Handler h1 = new Handler1(),
h2 = new Handler2(),
h3 = new Handler3(),
h4 = new Handler4();
h1.setNext(h2).setNext(h3).setNext(h4);
h1.request();
如果转化为if...else if 调用,客户端的代码会类似于如下,随着他们判断处理的环节越多,这种条件判断就随之增多,并且,和上面的代码比起来,没法让我们随心所欲的组合他们的条件处理顺序
if(...){
//....
}else if(...){
//....
}else if(...){
//....
}
优化 v2
编写的时候,发现是可以在套用一下 模版模式 对整个处理流程进行一定的优化
abstract class Handler {
private Handler next;
public void do(){
if(condition()){ // 满足条件,自己处理
request();
}else if(next != null){
next.do(); // 不满足条件,传递给下一个处理
}else{
defaultDo();
}
}
public void defaultDo(){// 默认的处理方式,当没有下一个,并且不满足条件时,执行
System.out.println("not find next!")
}
public abstract void condition();
public abstract void request();
public Handler setNext(Handler next){
this.next = next;
return next;
}
}
现在的子类实现就能变得更加专注
class Handler1 extends Handler {
public void condition(){
// 需要满足什么条件
}
public void request(){
// 在条件满足的情况下,需要如何做
}
// 如果我们对默认的处理方式不满意,还可以重写他
@Override
public void defaultDo(){}
}
当然,这么优化后,客户端的调用并没有什么变化。相当于 v1 版本,我们将子类自己做的逻辑判断,全部提取到了父类
灵活应用设计模式,吧变化的和不变的拆出来分别管理,代码也会显得更加有条理