设计模式 之 责任链模式

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

前言

搜了一圈责任链模式的文章,要么搬出 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() 方法的参数换成你自己的业务参数,马上就能用。

相关推荐
阿文的代码库7 小时前
桥接设计模式的案例实现
设计模式
乐观的山里娃8 小时前
【设计模式 14】责任链:谁来拍板
设计模式
乐观的山里娃20 小时前
【设计模式 08】装饰器:加钱加服务
设计模式
魔法阵维护师1 天前
从零开发游戏需要学习的c#模块,第十章(设计模式入门)
学习·游戏·设计模式·c#
用户356302904871 天前
【设计模式】组合模式——树形结构的统一处理
设计模式
JAVA学习通1 天前
《大营销平台系统设计实现》 - 营销服务 第7节:责任链模式处理抽奖规则
责任链模式
乐观的山里娃1 天前
【设计模式 12】原型:复制成功
设计模式
傻啦嘿哟1 天前
办公Agent与人工审核的“握手协议”:关键操作二次确认的设计模式
设计模式
hssfscv1 天前
软件设计师2021上、下上午题错题解析+2022上、下下午题训练5道 练习真题训练16
笔记·设计模式·uml