设计模式 之 责任链模式

一搜网上讲责任链的写法都感觉好复杂?我用简单实现让你秒懂并马上用到项目里

前言

搜了一圈责任链模式的文章,要么搬出 UML 类图画半天,要么搞一堆 HandlerHandlerChainAbstractHandler 层层嵌套,看得人头大。

今天分享一个我在实际项目中用的责任链实现,总共就 3 个核心文件,代码不超过 80 行,看完直接就能抄到你的项目里。


一、先说场景:什么时候需要责任链?

当你发现代码里有这种结构时:

java 复制代码
if (条件A) {
    // 处理逻辑 A
} else if (条件B) {
    // 处理逻辑 B  
} else if (条件C) {
    // 处理逻辑 C
} else {
    // 默认处理
}

每加一个场景就要改这个 if-else,越写越长,越改越乱。

责任链就是把这个 if-else 拆成一个个独立的处理节点,串起来依次执行。


二、核心就 3 个东西

角色 作用 对应文件
接口 定义"干什么"和"下一个是谁" ILogicChain
抽象类 帮你管好"下一个"的引用 AbstractLogicChain
实现类 每个节点的具体逻辑 ReBrushChain / ContextCacheChain / DefaultChain

三、代码逐行拆解

1. 接口 --- 定义链的契约

java 复制代码
public interface ILogicChain {

    // 核心方法:处理业务逻辑
    List<ShardingContext> logic(SalesOrderEnum type, MageFilter filter, MetaInfo meta);

    // 获取下一个节点
    ILogicChain next();

    // 追加下一个节点(返回被追加的节点,方便链式调用)
    ILogicChain appendNext(ILogicChain next);
}

关键点appendNext 返回的是 ILogicChain 而不是 void,这样工厂里可以 current = current.appendNext(next) 一路串下去。


2. 抽象类 --- 统一管理 next 引用

java 复制代码
@Slf4j
public abstract class AbstractLogicChain implements ILogicChain {

    private ILogicChain next;

    @Override
    public ILogicChain next() {
        return next;
    }

    @Override
    public ILogicChain appendNext(ILogicChain next) {
        this.next = next;
        return next;  // 返回下一个,方便链式组装
    }

    // 子类可以标识自己的规则名
    protected abstract String rule();
}

就这么简单。next 的存取全在抽象类里,子类完全不用关心链的维护。


3. 实现类 --- 每个节点只管自己的事

节点 1:反刷链(优先级最高)
java 复制代码
@Order(1)
public class ReBrushChain extends AbstractLogicChain {

    @Override
    protected String rule() {
        return "rebrush";
    }

    @Override
    public List<ShardingContext> logic(SalesOrderEnum type, MageFilter filter, MetaInfo meta) {
        // 命中我的场景 → 我处理,直接返回
        if (meta.reBrush()) {
           // ... 构建并返回 brushContextList
            return brushContextList;
        }

        // 不命中 → 交给下一个
        return next().logic(type, filter, meta);
    }
}
节点 2:上下文缓存链
java 复制代码
@Order(2)
public class ContextCacheChain extends AbstractLogicChain {

    @Override
    protected String rule() {
        return "context_cache";
    }

    @Override
    public List<ShardingContext> logic(SalesOrderEnum type, MageFilter filter, MetaInfo meta) {
        Object contextCacheValue = filter.getValue(CustomProperties.INTEGRATION_BATCH_SCOPE);
        
        // 命中 → 从缓存取 Scope,直接返回
        if (null != contextCacheValue) {
           
            // ... 构建并返回 contextList
            return contextList;
        }

        // 不命中 → 交给下一个
        return next().logic(type, filter, meta);
    }
}
节点 3:默认链(兜底)
java 复制代码
@Order(3)
public class DefaultChain extends AbstractLogicChain {

    @Override
    protected String rule() {
        return "default";
    }

    @Override
    public List<ShardingContext> logic(SalesOrderEnum type, MageFilter filter, MetaInfo meta) {
        // 兜底节点:直接查数据库拿 Scope
        List<ProcessDataScope> scopeList = db.get();

        return scopeList;
    }
}

注意 :DefaultChain 没有调用 next(),因为它是最后一个节点。


4. 工厂 --- 把链组装起来

java 复制代码
public class ScopeChainFactory {
    
    private static final Map<String, ILogicChain> CHAIN_GROUP = new HashMap<>();
    static {
        CHAIN_GROUP.put("rebrush", new ReBrushChain());
        CHAIN_GROUP.put("context_cache", new ContextCacheChain());
        CHAIN_GROUP.put("default", new DefaultChain());
    }

    // 定义执行顺序
    private static final String[] SCOPE_MODELS = new String[] { "rebrush", "context_cache" };

    public static ILogicChain openChain() {
        // 拿到头节点
        ILogicChain logicChain = CHAIN_GROUP.get(SCOPE_MODELS[0]);
        ILogicChain current = logicChain;

        // 依次串起来
        for (int i = 1; i < SCOPE_MODELS.length; i++) {
            ILogicChain nextChain = CHAIN_GROUP.get(SCOPE_MODELS[i]);
            current = current.appendNext(nextChain);
        }

        // default 兜底,确保链不会断
        current.appendNext(CHAIN_GROUP.get("default"));
        
        return logicChain;
    }
}

四、调用方怎么用?

一行代码:

java 复制代码
List<ShardingContext> result = ScopeChainFactory.openChain()
    .logic(salesType, filter, metaInfo);

调用方完全不用关心内部走了哪个节点,链会自己判断。


五、执行流程图

复制代码
调用入口
   ↓
ReBrushChain (Order=1)
   ├─ 命中反刷场景? → 处理并返回
   └─ 没命中 → next()
        ↓
ContextCacheChain (Order=2)
   ├─ 有上下文缓存? → 处理并返回
   └─ 没有缓存 → next()
        ↓
DefaultChain (Order=3, 兜底)
   └─ 查数据库拿 Scope → 处理并返回

六、和网上的写法比,简单在哪?

对比项 网上的写法 本文写法
类的数量 5-8 个(Handler、Chain、Builder、Context...) 3 个(接口、抽象类、实现类)
组装方式 Builder 嵌套 / Spring 注入 List 再排序 静态 Map + 数组定义顺序
传递方式 封装一个 Context 对象层层传递 方法参数直接传,清晰明了
终止条件 各种 boolean 返回值判断 命中就 return,没命中就 next()

七、要加新节点怎么办?

3 步:

  1. 新建实现类,继承 AbstractLogicChain,实现 logic() 方法
  2. ScopeChainFactoryCHAIN_GROUP 里注册
  3. SCOPE_MODELS 数组里加上它的位置

完事。不用改任何已有代码,符合开闭原则。


总结

责任链模式的本质就是:把 if-else 变成一串独立节点,每个节点自己决定"我处理"还是"交给下一个"。

不需要复杂的框架,不需要一堆辅助类。一个接口、一个抽象类、几个实现类、一个工厂,就够了。

直接抄到你的项目里,把 logic() 方法的参数换成你自己的业务参数,马上就能用。

相关推荐
atunet1 小时前
关于算法设计模式的演化与编程范式变迁的技术7
算法·设计模式
geovindu7 小时前
go:Timing Functions Pattern
开发语言·后端·设计模式·golang·计时函数模式·性能分析模式
咖啡八杯2 天前
GoF设计模式——备忘录模式
java·后端·spring·设计模式
槑有老呆2 天前
从 Prompt Engineering 到 Harness Engineering:AI 编程的下一次跃迁
设计模式
HjhIron2 天前
从Prompt到Context:大模型应用开发的范式转移
设计模式·aigc·ai编程
咖啡八杯4 天前
GoF设计模式——中介者模式
java·后端·spring·设计模式
胡萝卜术4 天前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
亦暖筑序5 天前
Java 8老系统Browser Agent实战:三层拦截把AI操作后台变成可审计流程
java·后端·设计模式
青禾网络7 天前
Web 前端如何接入 AI 音效生成:从零到可用的完整方案
人工智能·设计模式
ZJPRENO8 天前
吃透软件开发六大设计原则,告别烂代码
设计模式