58、职责链模式(上)

1、职责链模式的原理和实现

职责链模式的英文翻译是 Chain Of Responsibility Design Pattern,在 GoF 的《设计模式》中,它是这么定义的
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求,将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止

这么说比较抽象,我用更加容易理解的话来进一步解读一下

  • 在职责链模式中,多个处理器(也就是刚刚定义中说的 "接收对象")依次处理同一个请求
  • 一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条
  • 链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式

关于职责链模式,我们先来看看它的代码实现,结合代码实现,你会更容易理解它的定义
职责链模式有多种实现方式,我们这里介绍两种比较常用的

1.1、实现一

Handler 是所有处理器类的抽象父类,handle() 是抽象方法,每个具体的处理器类(HandlerA、HandlerB)的 handle() 函数的代码结构类似

  • 如果它能处理该请求,就不继续往下传递
  • 如果不能处理,则交由后面的处理器来处理,也就是调用 successor.handle()

HandlerChain 是处理器链,从数据结构的角度来看,它就是一个记录了链头、链尾的链表(记录链尾是为了方便添加处理器)

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;
        System.out.println("A 处理");
        // ...
        return handled;
    }
}


public class HandlerB extends Handler {
    @Override
    protected boolean doHandle() {
        boolean handled = false;
        System.out.println("B 处理");
        // ...
        return handled;
    }
}
/**
 * handler 的单向链表
 * 从 tail 添加
 * 从 head 处理
 */
public class HandlerChain {

    private Handler head = null;
    private Handler tail = null;

    public void addHandler(Handler handler) {
        handler.setSuccessor(null);
        if (head == null) {
            head = 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();
    }
}

1.2、实现二

HandlerChain 类用数组而非链表来保存所有的处理器,并且需要在 HandlerChain 的 handle() 函数中,依次调用每个处理器的 handle() 函数

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) {
        handlers.add(handler);
    }

    public void handle() {
        boolean handled;
        for (IHandler handler : handlers) {
            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();
    }
}

1.3、更多实现

在 GoF 给出的定义中,如果处理器链上的某个处理器能够处理这个请求,那就不会继续往下传递请求
职责链模式还有一种变体,那就是请求会被所有的处理器都处理一遍,不存在中途终止的情况
这种变体也有两种实现方式:用链表存储处理器和用数组存储处理器,跟上面的两种实现方式类似,只需要稍微修改即可

2、职责链模式的应用场景举例

对于支持 UGC(User Generated Content 用户生成内容)的应用(比如论坛)来说
用户生成的内容(在论坛中发表的帖子)可能会包含一些敏感词(比如涉黄、广告、反动等词汇)
针对这个应用场景,我们就可以利用职责链模式来过滤这些敏感词

对于包含敏感词的内容,我们有两种处理方式

  • 直接禁止发布(符合 GoF 给出的职责链模式的定义)
  • 给敏感词打马赛克(用 *** 替换敏感词)之后再发布(职责链模式的变体)

2.1、代码

// 敏感字过滤器
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) {
        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 Application {

    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 {
            // 发表
        }
    }
}

2.2、解释

我们可以把上面的代码分成两类:框架代码和客户端代码

  • ApplicationDemo 属于客户端代码,也就是使用框架的代码
  • 除 ApplicationDemo 之外的代码属于敏感词过滤框架代码

假设敏感词过滤框架并不是我们开发维护的,而是我们引入的一个第三方框架,我们要扩展一个新的过滤算法,不可能直接去修改框架的源码
这个时候,利用职责链模式就能达到开篇所说的,在不修改框架源码的情况下,基于职责链模式提供的扩展点,来扩展新的功能
除此之外,利用职责链模式相对于不用职责链的实现方式,还有一个好处,那就是配置过滤算法更加灵活,可以只选择使用某几个过滤算法

3、图示

image

posted @ 2023-07-09 12:01  lidongdongdong~  阅读(8)  评论(0编辑  收藏  举报