责任链模式

本文题图:Photo by Andrew Ridley on Unsplash

本文是设计模式系列文章中的第一篇。写下设计模式,是因为一次偶然的机会接触到责任链模式,在尝试利用责任链模式在系统中进行重构一部分的业务后,觉得设计模式甚至巧妙,于是萌发了通读刘伟关于设计模式的文章,并记录下自己的学习过程。fighting!!!

责任链

先上图,来一个看图说话,处理者 A 处理 A 类内容,处理者 B 处理 B 类内容。多个处理者之间建立单向连接关系。当任务开始分配的时候,并不直接分配给具体的处理者,而是交给所有处理对象中的第一位。将原本属于单一节点的处理过程交由所有处理对象共同解决,这就是责任链。

责任链的分类

  • 纯责任链
    1. 当任务进入责任链时,必须在当前链中进行消费;
    2. 不允许存在同一任务由多个处理者处理,例如:A 类内容经由处理者 A 处理过一部分后,成为可由处理者 B 处理的 B 类内容。
  • 不纯责任链
    1. 允许存在当前责任链不消费当前任务;
    2. 允许同一任务由多个处理者进行处理;

优缺点

  • 优点
    1. 可根据业务需要及时调整处理对象;
    2. 任务发出者无需知道以何种形式调度及具体的处理过程;
    3. 每个处理者节点仅维护下一处理者节点;
  • 缺点
    1. 当责任链配置不合理时,可能会出现死循环;
    2. 当存在较长的责任链时可能导致系统性受到严重;
    3. 不利于调试;

实战操作

前情提要

实际项目中,在与低功耗蓝牙进行交互时,有着严格的操作流程。具体为以下几个步骤:连接、打开通知、发送设备密钥、同步系统时间、检查系统时间、获取设备状态信息。这些业务内容不算复杂,由于早期项目追求产品迭代速度,而忽略了代码质量。导致产生了以下几个问题:

  1. 与项目中的其他业务高度黏合;
  2. 现有的设计不能满足于及时调整单一节点的数据处理;
  3. 多处蓝牙相关使用场景不能产生有效复用;
  4. 团对新人进入,学习成本较高;

思路

首先将蓝牙交互进行拆分,将具体的交互步骤分别拆分为责任链中的处理者。初步定下连接、打开通知、发送设备密钥、同步系统时间、检查系统时间、结束,这些处理者。

其次,我们需要一个组织管理者,用来添加处理者,并开始任务处理。具体的业务处理需要根据不同的需求进行处理,但彼此之间需要建立一种共性,方便组织管理者对其进行管理。这里选择新建一个抽象类作为所有的处理对象的父类。

ChainRoot.java

public abstract class ChainRoot<D> {
    private ChainRoot<D> nextChain;

    ChainRoot() {
    }

    public abstract void handle(int cmd, D data);

    void setNextChain(ChainRoot<D> chain) {
        this.nextChain = chain;
    }

    void toNext(int cmd, D data) {
        if (nextChain != null) {
            nextChain.handle(cmd, data);
        }
    }
}

ChainManager.java

public class ChainManager<D> {
    private ChainRoot<D> chain;

    private ChainManager(ChainRoot<D> chain) {
        this.chain = chain;
    }

    public void handle(int cmd, D data) {
        chain.handle(cmd, data);
    }

    public static class ChainBuilder<D> {
        private ChainRoot<D> header;
        private ChainRoot<D> tail;

        public ChainBuilder() {
            header = null;
            tail = null;
        }

        public ChainBuilder<D> addChain(ChainRoot<D> chain) {
            if (header == null) {
                this.header = chain;
                this.tail = chain;
            } else {
                this.tail.setNextChain(chain);
                this.tail = chain;
            }
            return this;
        }

        public ChainManager<D> build() {
            return new ChainManager<>(header);
        }

        public ChainManager<D> build(AndroidViewModel viewModel) {
            return new ChainManager<>(header);
        }
    }
}