责任链模式
责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一个链,并沿着这个链传递这个请求,直到有一个对象处理它。【DP】
客户端来定义链的结构,随时增加或修改处理一个请求的结构。增强了给对象指派职责的灵活性。[DP]
设计模式中有一个很经典又常用的模式即责任链模式,我们来仔细学习一下:
- 常见责任链模式
- okhttp责任链实现
常见责任链模式
以下例子来自w3cschool实现:
public class Request {
String level;
public Request(String level){
this.level = level;
}
public String getLevel(){
return level;
}
}
public class Response {
}
public abstract class Handler {
private Handler nextHandler;
public final Response handleRequest(Request request){
Response response = null;
if(this.getHandlerLevel().equals(request.getLevel())){
response = this.response(request);
}else{
if(this.nextHandler != null){
response = this.nextHandler.handleRequest(request);
}else{
System.out.println("-----没有合适的处理器-----");
}
}
return response;
}
public void setNextHandler(Handler handler){
this.nextHandler = handler;
}
protected abstract String getHandlerLevel();
public abstract Response response(Request request);
}
public class ConcreteHandler1 extends Handler {
@Override
protected String getHandlerLevel() {
return "1";
}
@Override
public Response response(Request request) {
System.out.println("-----请求由处理器1进行处理-----");
return new Response();
}
}
public class ConcreteHandler2 extends Handler {
@Override
protected String getHandlerLevel() {
return "2";
}
@Override
public Response response(Request request) {
System.out.println("-----请求由处理器2进行处理-----");
return new Response();
}
}
public class ConcreteHandler3 extends Handler {
@Override
protected String getHandlerLevel() {
return "3";
}
@Override
public Response response(Request request) {
System.out.println("-----请求由处理器3进行处理-----");
return new Response();
}
}
public class Client {
public static void main(String[] args){
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
handler1.setNextHandler(handler2);
handler2.setNextHandler(handler3);
Response response = handler1.handleRequest(new Request("3"));
}
}
okhttp责任链实现(简化版)
以下代码来自okhttp源码,经过简化后得到的:
public class Request {
}
public class Response {
}
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
}
}
public final class ConnectInterceptor implements Interceptor {
public ConnectInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
System.out.println("ConnectInterceptor");
return chain.proceed(chain.request());
}
}
public final class CallServerInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
System.out.println("CallServerInterceptor");
return new Response();
}
}
public final class RealInterceptorChain implements Interceptor.Chain {
private final List<Interceptor> interceptors;
private final int index;
private final Request request;
public RealInterceptorChain(List<Interceptor> interceptors, int index, Request request) {
this.interceptors = interceptors;
this.index = index;
this.request = request;
}
@Override
public Request request() {
return request;
}
@Override
public Response proceed(Request request) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors,index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
return response;
}
}
public class Client {
public static void main(String[] args) throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
interceptors.add(new ConnectInterceptor());
interceptors.add(new CallServerInterceptor());
Request originalRequest = new Request();
Interceptor.Chain chain = new RealInterceptorChain(interceptors,0,originalRequest);
Response response = chain.proceed(originalRequest);
}
}
说明:okhttp真实源码(本文中已经省略了)中CallServerInterceptor间接依赖于ConnectInterceptor产生的exchange,真实实现是非标准的。
后记
责任链模式是不分标准和非标准的,我自己定义了标准实现,其它是变种:
- request没有在链式处理中变更
- 有且一定仅有一个对象处理请求
- 链式路径是链式,不是树形或者其它数据结构,换句话说在链式处理中除开抛异常和直接返回,没有改变流程即新建分支流程
- 链式处理器对象之间没有直接或间接依赖
思考:
- 责任链模式处理时request可以改变吗?
- 链式数据结构可以是其它吗?
- 链式流程分支可以改变吗?
- 对于request请求可以多对象处理吗?
- 链式处理器可以相互依赖吗?
- 一定要在客户端(使用时)定义链吗?
代码上实现思考中提到的问题很简单,然而带来好处的同时也会产生各种副作用,大家可以思考一下,根据实际情况选用。一般框架中用到的都是标准实现的变种,也就是非标准实现,后面如果碰到其它框架责任链模式,在补充一下。
这里声明一下:标准实现和非标准实现都有各自的优劣势,请根据实际情况选择。
本文参考了以下文档:
- w3cschool
- 《设计模式:可复用面向对象软件的基础》【DP】
- 《设计模式之禅》
- 《大话设计模式》