设计模式 责任链模式(Chain of Responsibility)

博文目录


责任链模式

Chain of Responsibility

责任链模式是将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求,如果能则处理,如果不能则传递给链上的下一个对象。

用通俗的话来解释上面的定义:在责任链模式中,多个处理器(也就是定义中说的“对象”)依次处理同一个请求。一个客户端请求先经过处理器A处理,然后再把请求传递给处理器B,处理器B处理完后再传递给处理器C,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理责任,所以叫作责任链模式。

理解思想

Servlet Filter 是一个比较好的模型, 客户端发出请求, 通过过滤器链的层层处理, 到达核心Servlet, Servlet做了核心业务逻辑后得到了响应, 再通过过滤器链的层层处理, 最终回到客户端

需要注意的是, 每个过滤器都可以发挥两次作用, 分别是调用链中下一个过滤器处理的前与后, 前者通常都是只处理Request参数, 后者则通常只处理Response响应

在这里插入图片描述

优缺点

  • 优点
    • 满足开闭原则,提高代码的扩展性, 添加新的规则时, 只需要添加对应的规则类即可, 无需修改原有逻辑
    • 更好地处理代码的复杂性, 将大块代码逻辑拆分函数,将大类拆成小类,是应对代码复杂性的常用方法
    • 避免请求的送发者和接收者之间的耦合关系, 发送者将请求发送给链而不是指定某一个接收者
  • 缺点
    • 不能保证每个请求一定被处理, 由于请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理
    • 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能可能受到一定影响

实现方式

常见的责任链实现方式有两种

  • 自建链表: 处理器持有下一个处理器的引用, 通常用于有强烈先后顺序关系的责任链中. 举例: 审核流程通常从最底层开始审核, 有权限审核的就操作审核通过或不通过, 没有权限的则交给下一层更高级的权限者审核
  • 使用现成的链表, 如 LinkedList: 在链表中加入各个处理器, 依次调用每个处理器的处理方法, 常用于先后关系不敏感的责任链中, 或者需要自行指定添加顺序的责任链中

变种说明

责任链的变种有很多

  • 通传式: 链中的每个处理器都要过一遍
  • 截断式: 链中的某个处理器处理过后, 则直接返回结果, 不再向后传递

写法说明

责任链的写法不固定

  • 入参和出参不一定有, 看情况而定
  • 链中的处理器, 有的会将入参和结果都处理一遍, 有的则只处理入参, 有的则只处理结果, 有的则只是打印一些内容, 不对入参和结果做任何处理, 非常灵活
  • 有的会把入参和结果都写到处理器的参数中, 这时函数的返回值就是 void, 有的则在处理器的参数中只写入参, 返回值通过函数返回

举例

Servlet Filter 模拟

package com.mrathena.design.pattern.行为型.责任链模式.完整式;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public class Test {

    // 模拟 Servlet Filter 责任链实现

    public static void main(String[] args) {
        Map<String, Object> request = new HashMap<>();
        Map<String, Object> response = new HashMap<>();
        FilterChain chain = new FilterChain(new Servlet());
        chain.addFilter(new CheckUsernamePasswordFilter());
        chain.addFilter(new CheckTypeFilter());
        chain.addFilter(new DesensitizeFilter());
        // 准备数据
        request.put("username", "username");
        request.put("password", "password");
        request.put("type", "token");
        request.put("type", "phone");
        // 传入过滤器链
        chain.doFilter(request, response);
        // 打印结果
        System.out.println(response);
    }
}

interface Filter {
    void doFilter(Map<String, Object> request, Map<String, Object> response, FilterChain chain);
}

class Servlet {
    public void service(Map<String, Object> request, Map<String, Object> response) {
        System.out.println("----------");
        System.out.println("参数: " + request);
        String type = (String) request.get("type");
        if ("phone".equals(type)) {
            response.put("phone", "18212345678");
        }
        if ("token".equals(type)) {
            response.put("token", UUID.randomUUID().toString().replace("-", ""));
        }
        System.out.println("结果: " + response);
        System.out.println("----------");
    }
}

class FilterChain {
    public FilterChain(Servlet servlet) {
        this.servlet = servlet;
    }
    private final List<Filter> list = new LinkedList<>();
    private final Servlet servlet;
    private int index;
    public void addFilter(Filter filter) {
        for (Filter item : list) {
            if (item == filter) {
                return;
            }
        }
        list.add(filter);
    }
    public void doFilter(Map<String, Object> request, Map<String, Object> response) {
        if (index < list.size()) {
            Filter filter = list.get(index++);
            filter.doFilter(request, response, this);
        } else {
            servlet.service(request, response);
        }
    }
}

class CheckUsernamePasswordFilter implements Filter {
    @Override
    public void doFilter(Map<String, Object> request, Map<String, Object> response, FilterChain chain) {
        String username = (String) request.get("username");
        if (null == username) {
            response.put("message", "username not exist");
            return;
        }
        String password = (String) request.get("password");
        if (null == password) {
            response.put("message", "password not exist");
            return;
        }
        if (!("username".equals(username) && "password".equals(password))) {
            response.put("message", "username or password is not correct");
            return;
        }
        chain.doFilter(request, response);
    }
}

class CheckTypeFilter implements Filter {
    @Override
    public void doFilter(Map<String, Object> request, Map<String, Object> response, FilterChain chain) {
        String type = (String) request.get("type");
        if (null == type) {
            response.put("message", "type not exist");
            return;
        }
        if (!("phone".equals(type) || "token".equals(type))) {
            response.put("message", "type value is not correct");
            return;
        }
        chain.doFilter(request, response);
    }
}

class DesensitizeFilter implements Filter {
    @Override
    public void doFilter(Map<String, Object> request, Map<String, Object> response, FilterChain chain) {
        chain.doFilter(request, response);
        String phone = (String) response.get("phone");
        if (null != phone) {
            StringBuilder sb = new StringBuilder(phone);
            sb.replace(3, 7, "****");
            response.put("phone", sb.toString());
        }
    }
}

通传式 关键字屏蔽

自建链表

package com.mrathena.design.pattern.行为型.责任链模式.通传式.自建链表;

public class Test01 {

    // 自建链表

    // 举例, 小说的屏蔽字词替换工具
    // 八九, 十之八九->十之**
    // 体位, 具体位置->具**置
    // 西藏, 东躲西藏->东躲**
    // 色诱, 景色诱人->景**人
    // 国军, 中国军人->中**人

    public static void main(String[] args) {
        String string = "驻守在西藏的中国军人是伟大的, 在那严酷的自然环境中, 他们将重重困难克服了十之八九, 保证了祖国边疆的安稳";
        Handler handler = new Handler01().next(new Handler02().next(new Handler03()));
        String result = handler.handle(string);
        System.out.println(result);
    }
}

abstract class Handler {
    private Handler next = null;
    public Handler next(Handler handler) {
        this.next = handler;
        return this;
    }
    public abstract String replace(String string);
    public String handle(String string) {
        // 在数据从前向后传递给下一个Handler前可以做一些操作
        String result = replace(string);
        if (null == this.next) {
            return result;
        }
        // 将当前Handler处理后的数据交给下一个Handler处理
        result = next.handle(result);
        // 在结果从后向前返回给上一个Handler前也可以做一些操作
        return result;
    }
}

class Handler01 extends Handler {
    @Override
    public String replace(String string) {
        return string.replace("八九", "**");
    }
}

class Handler02 extends Handler {
    @Override
    public String replace(String string) {
        return string.replace("西藏", "**");
    }
}

class Handler03 extends Handler {
    @Override
    public String replace(String string) {
        return string.replace("国军", "**");
    }
}

使用现成链表

package com.mrathena.design.pattern.行为型.责任链模式.通传式.使用链表;

import java.util.LinkedList;
import java.util.List;

public class Test02 {

    // 使用 List

    // 举例, 小说的屏蔽字词替换工具
    // 八九, 十之八九->十之**
    // 体位, 具体位置->具**置
    // 西藏, 东躲西藏->东躲**
    // 色诱, 景色诱人->景**人
    // 国军, 中国军人->中**人

    public static void main(String[] args) {
        String string = "驻守在西藏的中国军人是伟大的, 在那严酷的自然环境中, 他们将重重困难克服了十之八九, 保证了祖国边疆的安稳";
        HandlerChain chain = new HandlerChain();
        chain.add(new Handler01());
        chain.add(new Handler02());
        chain.add(new Handler03());
        String result = chain.handle(string);
        System.out.println(result);
    }
}

interface Handler {
    String handle(String string);
}

class Handler01 implements Handler {
    @Override
    public String handle(String string) {
        return string.replace("八九", "**");
    }
}

class Handler02 implements Handler {
    @Override
    public String handle(String string) {
        return string.replace("西藏", "**");
    }
}

class Handler03 implements Handler {
    @Override
    public String handle(String string) {
        return string.replace("国军", "**");
    }
}

class HandlerChain {
    private final List<Handler> list = new LinkedList<>();
    public void add(Handler handler) {
        list.add(handler);
    }
    public String handle(String string) {
        String result = string;
        for (Handler handler : list) {
            result = handler.handle(result);
        }
        return result;
    }
}

截断式 请假审批流程

package com.mrathena.design.pattern.行为型.责任链模式.截断式;

public class Test {
    public static void main(String[] args) {
        int days = 31;
        Reviewer reviewer = new Leader().next(new Manager().next(new Boss()));
        reviewer.review(days);
    }
}

abstract class Reviewer {
    protected Reviewer next = null;
    public Reviewer next(Reviewer reviewer) {
        this.next = reviewer;
        return this;
    }
    public abstract void review(int days);
}

class Leader extends Reviewer {
    @Override
    public void review(int days) {
        if (days <= 3) {
            System.out.println("Leader review pass");
            return;
        }
        next.review(days);
    }
}

class Manager extends Reviewer {
    @Override
    public void review(int days) {
        if (days <= 7) {
            System.out.println("Manager review pass");
            return;
        }
        next.review(days);
    }
}

class Boss extends Reviewer {
    @Override
    public void review(int days) {
        if (days <= 30) {
            System.out.println("Boss review pass");
        } else {
            System.out.println("Boss review not pass");
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值