之前,我们说了模板模式,策略模式,现在则是责任链模式,这个模式其本质上也是为了提高代码的复用和扩展,在实际项目开发中比较常用,来定制化框架
在Spring中,Servlet Filter,Spring Interceptor都是用了责任链的设计模式
其定义为,将请求的接收和发送解耦,让多个接受对象都可以有机会进行处理,将这些接收对象串成一个链表,直到链表到头或者某个接收对象接收为止
也就是,一个链表上A-B-C,一个请求过来了,A去处理,没成,B去处理,一直到尽头
链表上每个处理器承担各自的处理职责,这就是职责链模式
常见的实现方式有两种
1.完完全全的按照链表
Handler是所有处理器的父类,然后其中handler是抽象方法,由其中确定,能不能调用
接下来的处理器去处理请求,successor.handler() HandlerChain,是一个链表,也就是处理器链
public abstract class Handler { protected Handler successor = null; public void setSuccessor(Handler successor) { this.successor = successor; } public abstract void handle(); } public class HandlerA extends Handler { @Override public boolean handle() { boolean handled = false; //… if (!handled && successor != null) { successor.handle(); } } } public class HandlerB extends Handler { @Override public void handle() { boolean handled = false; //… if (!handled && successor != null) { successor.handle(); } } } public class HandlerChain { private Handler head = null; private Handler tail = null; public void addHandler(Handler handler) { handler.setSuccessor(null); if (head == null) { head = handler; tail = handler; return; } tail.setSuccessor(handler); tail = handler; } public void handle() { if (head != null) { head.handle(); } } } // 使用举例 public class Application { public static void main(String[] args) { HandlerChain chain = new HandlerChain(); chain.addHandler(new HandlerA()); chain.addHandler(new HandlerB()); chain.handle(); } } |
但是,上面的方法可以继续进行优化,也就是调用下一个处理器的succesor.handler().导致代码出现了bug,针对这个问题,应该对代码进行重构,将successor.handler()的逻辑从中剥离,根据doHandler()的返回值来进行确定是否调用,重构后的代码如下
public abstract class Handler { protected Handler successor = null; public void setSuccessor(Handler successor) { this.successor = successor; } public final void handle() { boolean handled = doHandle(); if (successor != null && !handled) { successor.handle(); } } protected abstract boolean doHandle(); } public class HandlerA extends Handler { @Override protected boolean doHandle() { boolean handled = false; //… return handled; } } public class HandlerB extends Handler { @Override protected boolean doHandle() { boolean handled = false; //… return handled; } } |
// HandlerChain和Application代码不变
接下来是第二种实现方式,直接使用数组,实现方式更加简单,HandlerChain类使用数组而不是链表保存,这样只需要依次的调用即可
public interface IHandler { boolean handle(); } public class HandlerA implements IHandler { @Override public boolean handle() { boolean handled = false; //… return handled; } } public class HandlerB implements IHandler { @Override public boolean handle() { boolean handled = false; //… return handled; } } public class HandlerChain { private List<IHandler> handlers = new ArrayList<>(); public void addHandler(IHandler handler) { this.handlers.add(handler); } public void handle() { for (IHandler handler : handlers) { boolean handled = handler.handle(); if (handled) { break; } } } } // 使用举例 public class Application { public static void main(String[] args) { HandlerChain chain = new HandlerChain(); chain.addHandler(new HandlerA()); chain.addHandler(new HandlerB()); chain.handle(); } } |
利用foreach循环,在某个处理器能够处理的时候,就不会继续往下传递请求,
而真正的责任链模式中,还有一种变体,就是所有的处理器都会进行一次处理,中途不会停止,
也是可以利用链表或者数组来进行存储处理,只需要稍微进行修改就行
我们给出了一种链表的实现方式,其本质就是去掉了判断是否继续执行,依次执行即可
public abstract class Handler { protected Handler successor = null; public void setSuccessor(Handler successor) { this.successor = successor; } public final void handle() { doHandle(); if (successor != null) { successor.handle(); } } protected abstract void doHandle(); } public class HandlerA extends Handler { @Override protected void doHandle() { //… } } public class HandlerB extends Handler { @Override protected void doHandle() { //… } } public class HandlerChain { private Handler head = null; private Handler tail = null; public void addHandler(Handler handler) { handler.setSuccessor(null); if (head == null) { head = handler; tail = handler; return; } tail.setSuccessor(handler); tail = handler; } public void handle() { if (head != null) { head.handle(); } } } // 使用举例 public class Application { public static void main(String[] args) { HandlerChain chain = new HandlerChain(); chain.addHandler(new HandlerA()); chain.addHandler(new HandlerB()); chain.handle(); } } |
那么,使用职责链模式的场景就很简单了
比如,一个论坛中发表中可能包含一些敏感词,针对这个场景,可以利用职责链模式来进行敏感词过滤,针对过滤词来进行过滤的手段有两种,一种是直接禁止发布,一种是给敏感词打马赛克
这就是分别为拦截处理一次,和依次处理走下去
我们这里给出了第一种的实现方式,我们只给了代码实现的骨架,具体的过滤算法没有给出
public interface SensitiveWordFilter { boolean doFilter(Content content); } public class SexyWordFilter implements SensitiveWordFilter { @Override public boolean doFilter(Content content) { boolean legal = true; //… return legal; } } // PoliticalWordFilter、AdsWordFilter类代码结构与SexyWordFilter类似 public class SensitiveWordFilterChain { private List<SensitiveWordFilter> filters = new ArrayList<>(); public void addFilter(SensitiveWordFilter filter) { this.filters.add(filter); } // return true if content doesn’t contain sensitive words. public boolean filter(Content content) { for (SensitiveWordFilter filter : filters) { if (!filter.doFilter(content)) { return false; } } return true; } } public class ApplicationDemo { public static void main(String[] args) { SensitiveWordFilterChain filterChain = new SensitiveWordFilterChain(); filterChain.addFilter(new AdsWordFilter()); filterChain.addFilter(new SexyWordFilter()); filterChain.addFilter(new PoliticalWordFilter()); boolean legal = filterChain.filter(new Content()); if (!legal) { // 不发表 } else { // 发表 } } } |
但是,有一个问题,如果我们不使用责任链模式,也可以实现这个功能,那么,为什么要是用责任链模式呢?
因为使用责任链模式降低了复杂度,责任链模式将大块逻辑拆分为了小块的,并且拆分为了类,进一步的简化了SensitiveWordFilter类,让其只是一个客户端,不包含具体的代码逻辑
而且更加符合开闭原则,提高了代码的扩展性
当我们修改或者扩展新的过滤算法的时候,我们还要修改调用类的代码,这样违背了开闭员职责,而这责任链的实现方式更加优雅,只需要新添加一个Filter类即可,而且通过addFilter()函数放到FilterChain类中即可
不过细化一下,我们将代码分为两类,分为了客户端代码和框架代码,两者彼此分离,客户端代码只负责调用,不和任何逻辑耦合,框架代码留有扩展点,可以方便扩展
在增加一个新的过滤算法的时候,职责链模式就可以直接添加进去,不需要修改其他的代码
本章总结
责任链模式中,多个处理器处理一个请求,形成了一个链表,让A处理完传给B ,B->C
每个处理器可以只承担自己的处理职责
在定义当中,一旦一个处理器能够处理了,就不传递给后续的处理器了,但是存在着一个变体,中途不会停止传递,而是一直走到尾
而职责链模式有两种常见的实现方式,一种是链表来存储处理器,一种是数组来存储处理器