3/24 设计模式之责任链设计模式 Chain Of Responsibility Pattern

2020/3/1 posted in  设计模式 JAVA

类别:行为型设计模式

目的:将为了达成共同目标的一系列具有逻辑顺序的操作进行解耦

完整代码参考:https://1drv.ms/u/s!AquRvPzqx59Ri3IZYwf83oLFp6Pu?e=i6yxH7

典型场景

为一个web请求定义的一些列操作,比如

  1. 用户登陆验证
  2. 处理业务逻辑
  3. 压缩响应数据

注意以上3个操作是顺序的,需要登陆成功后再执行业务逻辑,业务逻辑生成响应数据后,才需要压缩响应数据

构造一个简单的http请求对象备用,参考:

public class HttpRequest {
    private String username;
    private String password;

    public HttpRequest(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }
}

硬编码

1 . 用户登陆认证

public class Authenticator {
    public boolean doHandle(HttpRequest request) {
        var isValid = (request.getUsername() == "admin" &&
                request.getPassword() == "1234");

        System.out.println("Authentication");

        return !isValid;
    }
}

2 . 处理业务逻辑

public class BusinessLogic {
    public boolean doHandle(HttpRequest request) {
        System.out.println("Log");

        return false;
    }
}

3 . 压缩响应数据

public class Compressor {
    public boolean doHandle(HttpRequest request) {
        System.out.println("Compress");

        return false;
    }
}

很容易写出下面的流程处理代码:

var request = new HttpRequest("root", "root");
var auth = new Authenticator();
var businessLogic = new BusinessLogic();
var compressor = new Compressor();
if (!auth.doHandle(request)) {
    if (!businessLogic.doHandle(request)) {
        compressor.doHandle(request);
    } else {
        // 处理结束
    }
} else {
    // 处理结束
}

可以看到随着处理步骤的增加,上面代码的混乱程度会越来越验证,特别是对于处理http请求这种步骤可能多达2、30个的复杂流程来说,这块代码将变得很难维护

模式实现

责任链的解决方式是,在每个流程处理class中持有下个处理流程的引用,通过判断当前流程是否成功,来决定是否调用下个处理流程

代码

每个流程持有的下个流程的引用、以及判断是否调用下个流程的代码实现可以放到处理流程的父类中,参考 Handler.java

public abstract class Handler {
    private Handler next;

    public Handler(Handler next) {
        this.next = next;
    }

    public void handle(HttpRequest request) {
        if (doHandle(request))
            return;

        if (next != null)
            next.handle(request);
    }

    public abstract boolean doHandle(HttpRequest request);
}

对下个流程的引用通过构造函数传递进来,通过调用hand()方法间接调用当前流程doHandle方法进行流程处理

所有的流程处理类继承这个Handler即可,拿BusinessLogic举例,参考:

public class BusinessLogic extends Handler {
    public BusinessLogic(Handler next) {
        super(next);
    }

    @Override
    public boolean doHandle(HttpRequest request) {
        System.out.println("Log");

        return false;
    }
}

然后依次处理Authenticator.java、Compressor.java

然后创建和使用这些流程

var compressor = new Compressor(null);
var businessLogic = new BusinessLogic(compressor);
var authenticator = new Authenticator(businessLogic);

var httpRequest = new HttpRequest("root", "root");
authenticator.handle(httpRequest);

可以看到把if判断的逻辑代码分散到了各自的流程处理类中,主流程更清晰了

UML

为什么责任链模式更好

  1. 分解逻辑判断的复杂度
  2. 使用者可以灵活选择不同的处理流程、调整处理顺序
  3. 新流程非常容易加入(集成Handler类即可)

一些注意的点

流程处理方法doHandle中返回值表示流程处理是否结束,true表示结束,false表示未结束,返回true后就不需要再执行下面的流程了

参考资料

  1. https://www.geeksforgeeks.org/chain-responsibility-design-pattern/