设计模式---责任链模式

简述

将各个功能拆分后分别封装(各功能解耦),需要时可自由组合(包括执行顺序)

话不多说,看个优化案例吧。

优化案例

最初版

以下是模拟客户端想服务端发送请求的业务流程。

客户端调用代码如下。

// 客户端
public class Client {
    public static void main(String[] args) {
        Map<String, String> request = new HashMap<>();
        request.put("username", "admin");
        request.put("password", "admin");
        service(request);
    }
    public static void service(Map<String, String> request) {
        String username = request.get("username");
        String password = request.get("password");
        if (!"admin".equals(username) || !"admin".equals(password)) {
            throw new RuntimeException("用户名或密码不正确!");
        }
        System.out.println("用户认证通过。");
        System.out.println("正在处理请求的业务。");
    }
}

如果根据新的需求,需要在用户认证通过到处理请求的业务之间增加一个缓存用户信息至Session的处理该怎么办,传统的写法肯定是直接在上述代码的第14行后加入一条缓存用户信息的处理,但这样下去,以后每次增加这部分的需求是都无一例外的需要修改客户端的代码,并且实际上客户端发送请求的方法肯定不止一处,如果有一个新业务是需要在每个请求的方法中都添加呢。那又怎么办?现在上面的代码只是模拟,所以只需要加一行打印输出即可,真实的逻辑可比这复杂得多,到时候的代码量也是现在的好几倍,岂不麻烦死了?

为了解决这个问题,我们可以使用责任链模式。

修改版v1

增加一组类,使用责任链模式。如下。

// 责任链的顶级接口
// 定义责任链的核心功能
public interface Chain {
    // 指定下一个处理
    void setNext(Chain next);
    // 处理当前请求
    void handler(Map<String, String> request);
}
// 责任链的抽象父类
// 定义所有责任链对象共通的属性和方法
public abstract class AbstractChain implements Chain {
    // 持有下一个处理
    private Chain next;
    public Chain getNext() {
        return next;
    }
    @Override
    public void setNext(Chain next) {
        this.next = next;
    }
}
// 用户认证模块
public class AuthChain extends AbstractChain {
    @Override
    public void handler(Map<String, String> request) {
        String username = request.get("username");
        String password = request.get("password");
        if (!"admin".equals(username) || !"admin".equals(password)) {
            throw new RuntimeException("用户名或密码不正确!");
        }
        System.out.println("用户认证通过。");
        Chain next = this.getNext();
        if (next == null) {
            throw new RuntimeException("处理中断!");
        }
        next.handler(request);
    }
}
// Session缓存模块
public class SessionChain extends AbstractChain {
    @Override
    public void handler(Map<String, String> request) {
        System.out.println("缓存用户信息至Session。");
        Chain next = this.getNext();
        if (next == null) {
            throw new RuntimeException("处理中断!");
        }
        next.handler(request);
    }
}
// 业务处理模块
public class ProcessChain extends AbstractChain {
    @Override
    public void handler(Map<String, String> request) {
        System.out.println("正在处理请求的业务。");
    }
}

修改后,客户端代码的调用如下。

public class Client {
    public static void main(String[] args) {
        Map<String, String> request = new HashMap<>();
        request.put("username", "admin");
        request.put("password", "admin");
        service(request);
    }
    public static void service(Map<String, String> request) {
        Chain auth = new AuthChain();
        Chain session = new SessionChain();
        Chain process = new ProcessChain();
        auth.setNext(session);
        session.setNext(process);
        auth.handler(request);
    }
}

熟悉数据结构的同学肯定一眼就看出了责任链模式的本质:链表。将一个冗长的业务处理流程拆分成各个模块,使用时根据业务流程以链表的形式将其串联。不仅提升了各个模块代码的复用性,而且还能是的各个模块自由组合,极大的提升了开发效率。

总结

优点

  • 可以自由指定各个模块的执行顺序。
  • 各个模块遵循单一职责使得各个模块间解耦。
  • 新增业务流程时只需要增加新的模块即可,遵循开闭原则,提升了系统的可维护性。

缺点

  • 当业务流程过长时,组成的业务链也会非常的长,涉及到的对象过多可能会影响系统的性能。
  • 虽然各个模块可以自由组合,但是组合的工作实际上都放在了客户端,这无疑提升了客户端的代码复杂度。

适用场景

  • 业务流程类的功能都可以使用责任链模式。
    • 公司或政府部门各级对于文件的审批,需要各级各部门盖章签字,并且其中一环未通过就得打回重新审核。
点赞