从组合爆炸到优雅分派:复杂策略系统的工程化构建

干货分享,感谢您的阅读!在实际的工程系统中,我们经常遇到这样的场景:

  • 推荐系统需要根据用户类型、内容标签、来源渠道、活动配置等组合选择不同策略;
  • 风控系统需要根据地区、设备、交易类型、时间段来执行不同规则;
  • 广告投放平台需要根据预算层级、素材类型、投放环境等参数自动选择出价逻辑。

这类问题的共同特点是:

  • 维度多(组合爆炸)

  • 策略多(共用与特例并存)

  • 易变(新场景不断增加)

于是,大厂开始频繁地在面试中抛出类似的“策略组合分派系统设计题”,考察候选人的系统抽象能力、代码组织能力与工程可扩展性思维

公司常见题型方向设计考察点
字节跳动(抖音、头条)推荐/广告策略系统;特征组合策略匹配注解注册、组合分派、优先级策略
阿里巴巴(淘系、蚂蚁)营销/风控/规则引擎设计规则抽象、DSL匹配、策略落地与容器化
腾讯(广告、视频号)用户画像 + 多维策略投放系统策略复用与动态优先级
美团配送调度策略 / 智能推荐规则动态分派、参数维度建模
京东价格策略 / 优惠券适配 / 库存调度组合枚举 + 注解注册 + 策略路由
滴滴 / 高德路线规划 / 费用策略多维输入组合 + 最优策略选择
Shopee / Lazada营销活动策略选择国际化组合、规则解耦

当策略逻辑开始“乘法爆炸”,我们该如何在不崩溃的前提下,让系统依旧优雅?我在之前很早的博客中有讲解过简单的一些策略解法:

但是这种典型的 「策略组合 + 注解注册 + 策略分派」思维,基于粉丝求助,我想今天直接拿出来做一次博客分享:当策略逻辑开始“乘法爆炸”,我们该如何在不崩溃的前提下,让系统依旧优雅?

一、题目背景:复杂组合策略系统设计

在大型业务系统中,策略逻辑往往随着场景扩展而成倍增长。
例如,在推荐、活动、风控、广告、内容审核等系统中,不同的 用户类型(A)渠道来源(B)运行环境(C)触发场景(D)共同决定了最终的策略选择。

如果我们使用多层 if-else 或硬编码去处理这些分支,不仅难以维护,还极易引发逻辑冲突与策略回退问题。

为此,我们希望设计一个:

基于多维组合 + 注解注册 + 动态分派 的策略系统。

二、系统要求与考察点

(一)基础要求

模块说明
A一级维度(2 种)
B二级维度(3 种)
C环境配置(2 种)
D场景触发(4 种)

组合总数:2×3×2×4=48,我们需要支持:

  • 为特定组合分配专属策略;

  • 多组合共用一个策略;

  • 默认兜底策略;

  • 支持模糊匹配(如仅匹配 C、D);

  • 自动注册、自动分派;

  • 可扩展到 Spring 环境。

(二)设计考察点

维度说明
架构抽象能力策略接口 → 注册器 → 分派器,职责清晰
可扩展性新增枚举或策略无需修改核心逻辑
冲突检测当多个策略匹配时,选“最具体”策略
工程化能力支持 Spring 扫描、Bean 装配、单元测试
通用性可提炼成独立策略服务用于其他项目

三、核心架构设计

整个系统的设计可以类比为一个“策略中枢大脑”,当外部输入一组业务信息(A、B、C、D)时,它能自动找到最合适的策略实现并执行。

这套架构共分为 六个核心层次,每一层都承担着清晰的职责,层层解耦、自然协作

层级职责
1️⃣ 枚举定义定义 A/B/C/D 的取值
2️⃣ 组合类型定义 Combination
3️⃣ 策略接口统一执行规范
4️⃣ 策略注解通过 @StrategyFor 注册规则
5️⃣ 策略注册器自动扫描并注册策略
6️⃣ 策略分派器匹配最优策略并执行

我们可实现从“输入组合 → 自动选择策略 → 执行结果”的完整链路:

这一套架构的核心理念是:

用注解替代硬编码匹配,用分派器替代 if-else 嵌套。

通过“注册-匹配-执行”三步走,实现了一个可扩展、可热插拔的策略系统,新增策略时只需写一个新类 + 加一个注解,系统即可自动识别。

四、具体技术实现

(一)枚举与组合类设计

1. 具体枚举定义与实现

package org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums;
/**
 * @program: zyfboot-javabasic
 * @description: 条件类型A
 * @author: zhangyanfeng
 * @create: 2025-11-02 15:23
 **/
public enum AType {
    A1, A2
}
package org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums;
/**
 * @program: zyfboot-javabasic
 * @description: 条件类型B
 * @author: zhangyanfeng
 * @create: 2025-11-02 15:24
 **/
public enum BType {
    B1, B2, B3
}
package org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums;
/**
 * @program: zyfboot-javabasic
 * @description: 条件类型C
 * @author: zhangyanfeng
 * @create: 2025-11-02 15:24
 **/
public enum CType {
    C1, C2
}
package org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums;
/**
 * @program: zyfboot-javabasic
 * @description: 条件类型D
 * @author: zhangyanfeng
 * @create: 2025-11-02 15:24
 **/
public enum DType {
    D1, D2, D3, D4
}

2. 基本组合类定义

package org.zyf.javabasic.designpatterns.strategy.tiktok.base.types;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.AType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.BType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.CType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.DType;
/**
 * @program: zyfboot-javabasic
 * @description: 枚举组合类
 * @author: zhangyanfeng
 * @create: 2025-11-02 15:29
 **/
public class Combination {
    private AType a;
    private BType b;
    private CType c;
    private DType d;
    public Combination(AType a, BType b, CType c, DType d) {
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
    }
    public AType getA() {
        return a;
    }
    public BType getB() {
        return b;
    }
    public CType getC() {
        return c;
    }
    public DType getD() {
        return d;
    }
    @Override
    public String toString() {
        return String.format("%s|%s|%s|%s", a, b, c, d);
    }
}

(二)注解与策略接口

1. 基本注解设计

package org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.annotation;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.AType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.BType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.CType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.DType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * @program: zyfboot-javabasic
 * @description: 注解策略接口
 * @author: zhangyanfeng
 * @create: 2025-11-02 18:23
 **/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface StrategyFor {
    AType[] a() default {};
    BType[] b() default {};
    CType[] c() default {};
    DType[] d() default {};
}

2.基本策略接口设计

package org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.types.Combination;
/**
 * @program: zyfboot-javabasic
 * @description: 策略接口
 * @author: zhangyanfeng
 * @create: 2025-11-02 18:25
 **/
public interface Strategy {
    void execute(Combination combination);
}

(三)示例策略实现

我们通过多个策略实现类来展示策略系统的声明与复用。每个策略类都通过 @StrategyFor 注解标明其适配的组合条件:

  • StrategyAlpha:覆盖 A1 + {B1,B2} + C1 下的所有 D 情况;

  • StrategyC2D4:专门处理 C2D4 的组合,无视 A/B;

  • DefaultStrategy:不限制任何条件,作为兜底策略。

设计目标实现“最小化重复”与“高可读性”的策略复用。

package org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.impl;
import org.springframework.stereotype.Component;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.AType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.BType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.CType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.Strategy;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.annotation.StrategyFor;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.types.Combination;
/**
 * @program: zyfboot-javabasic
 * @description: 覆盖 A1 + {B1,B2} + C1 下的所有 D 情况;
 * @author: zhangyanfeng
 * @create: 2025-11-02 18:28
 **/
@StrategyFor(a = {AType.A1}, b = {BType.B1, BType.B2}, c = {CType.C1})
@Component
public class StrategyAlpha implements Strategy {
    @Override
    public void execute(Combination combination) {
        System.out.println("StrategyAlpha handling: " + combination);
    }
}
package org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.impl;
import org.springframework.stereotype.Component;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.CType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.DType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.Strategy;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.annotation.StrategyFor;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.types.Combination;
/**
 * @program: zyfboot-javabasic
 * @description: StrategyC2D4:专门处理 C2 且 D4 的组合,无视 A/B;
 * @author: zhangyanfeng
 * @create: 2025-11-02 18:32
 **/
@StrategyFor(c = {CType.C2}, d = {DType.D4})
@Component
public class StrategyC2D4 implements Strategy {
    @Override
    public void execute(Combination combination) {
        System.out.println("StrategyC2D4 handling: " + combination);
    }
}
package org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.impl;
import org.springframework.stereotype.Component;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.Strategy;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.annotation.StrategyFor;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.types.Combination;
/**
 * @program: zyfboot-javabasic
 * @description: 不限制任何条件,作为兜底策略。
 * @author: zhangyanfeng
 * @create: 2025-11-02 18:32
 **/
@StrategyFor
@Component
public class DefaultStrategy implements Strategy {
    @Override
    public void execute(Combination combination) {
        System.out.println("DefaultStrategy handling: " + combination);
    }
}

说明:

  • 可通过多个值覆盖多种组合;
  • 未指定字段表示通配所有值;

  • 默认策略作为兜底。

(四)策略注册器

StrategyRegistry 是连接“策略实现”和“策略分派”的桥梁,它让策略系统具备 自动化、可扩展、可维护 的工程化特性。具体代码如下:

package org.zyf.javabasic.designpatterns.strategy.tiktok.base.core.registry;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.Strategy;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.annotation.StrategyFor;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
 * @program: zyfboot-javabasic
 * @description: 策略注册器(核心组件)
 *
 * 【职责说明】
 * 该组件在系统启动阶段自动扫描 Spring 容器中所有实现了 Strategy 接口的 Bean,
 * 读取它们的 @StrategyFor 注解配置,并将“策略实例 + 匹配规则”注册到策略列表中。
 * 后续由策略分派器(StrategyDispatcher)进行策略匹配与执行。
 *
 * 【设计目标】
 * - 自动注册:免手工配置
 * - 解耦扩展:策略定义与业务分离
 * - 统一管理:集中维护策略元信息
 *
 * @author:
 * @create: 2025-11-02 18:37
 **/
@Component
public class StrategyRegistry implements ApplicationContextAware {
    /** Spring 上下文,用于获取所有 Strategy Bean */
    private ApplicationContext applicationContext;
    /** 策略注册表,存放系统内所有策略信息 */
    private final List strategies = new ArrayList<>();
    /**
     * 内部静态类,用于封装单个策略的注册信息:
     * 包含策略对应的注解(匹配规则)与策略实例(执行对象)
     */
    public static class RegisteredStrategy {
        private final StrategyFor annotation;
        private final Strategy instance;
        public RegisteredStrategy(StrategyFor annotation, Strategy instance) {
            this.annotation = annotation;
            this.instance = instance;
        }
        public StrategyFor getAnnotation() {
            return annotation;
        }
        public Strategy getInstance() {
            return instance;
        }
    }
    /**
     * 容器启动后自动执行
     *
     * 1. 从 Spring 容器中获取所有实现 Strategy 接口的 Bean;
     * 2. 判断是否标注了 @StrategyFor;
     * 3. 如果是,则解析注解并注册到策略列表;
     * 4. 最终打印所有已注册的策略信息。
     */
    @PostConstruct
    public void init() {
        // 获取容器中所有 Strategy 类型的 Bean
        Map beans = applicationContext.getBeansOfType(Strategy.class);
        // 遍历所有策略 Bean,解析注解并注册
        beans.values().forEach(strategy -> {
            Class clazz = strategy.getClass();
            if (clazz.isAnnotationPresent(StrategyFor.class)) {
                StrategyFor annotation = clazz.getAnnotation(StrategyFor.class);
                strategies.add(new RegisteredStrategy(annotation, strategy));
                System.out.println("[StrategyRegistry] 注册策略: " + clazz.getSimpleName());
            }
        });
        // 打印统计结果
        System.out.println("[StrategyRegistry] 共注册策略数量: " + strategies.size());
    }
    /**
     * 对外暴露所有注册策略
     * 供分派器(StrategyDispatcher)使用
     */
    public List getStrategies() {
        return strategies;
    }
    /**
     * 由 Spring 注入 ApplicationContext
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

StrategyRegistry 是策略组合系统的“信息中心”,它在整个架构中承担了 “策略收集器 + 注册中心” 的角色:

功能说明
自动发现系统启动后,自动扫描所有实现 Strategy 接口的策略类
注解解析从每个策略类的 @StrategyFor 注解中提取匹配条件
集中注册将策略实例与注解信息封装为 RegisteredStrategy 对象并缓存
提供查询为分派器提供统一的策略清单,便于执行阶段快速定位策略

设计优势:

  • 无需硬编码注册;

  • 符合“开闭原则”(新增策略仅需新建类 + 注解);

  • 可视化输出策略注册日志,方便排查;

  • 轻量高效,适配生产级 Spring 应用。

(五)策略分派器

StrategyDispatcher 是策略系统的「调度核心」,它让策略体系从“静态 if-else 判断”进化为动态、可配置、可演化的智能分派系统。具体实现如下:

package org.zyf.javabasic.designpatterns.strategy.tiktok.base.core.dispatcher;
import org.springframework.stereotype.Component;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.core.registry.StrategyRegistry;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.Strategy;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.annotation.StrategyFor;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.types.Combination;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
 * @program: zyfboot-javabasic
 * @description: 策略分派器(Strategy Dispatcher)
 *
 * 【职责说明】
 * 该组件是整个策略系统的“大脑”,负责根据输入的组合(A/B/C/D)信息,
 * 从注册中心中查找最匹配的策略实例,并将其分派执行。
 *
 * 【核心流程】
 * 1️⃣ 从注册中心获取所有已注册策略;
 * 2️⃣ 根据 @StrategyFor 注解规则过滤出匹配的策略;
 * 3️⃣ 若存在多个匹配,按“具体度”(specificity)降序排序;
 * 4️⃣ 返回最具体的策略;若无匹配,则回退到默认策略。
 *
 * 【特点】
 * - 注解驱动、动态匹配
 * - 自动优先选择“最具体”策略(即匹配条件最多者)
 * - 可检测策略冲突(防止多个策略规则重复)
 * - 支持默认策略兜底
 *
 * @author:
 * @create: 2025-11-02 18:39
 **/
@Component
public class StrategyDispatcher {
    /** 策略注册中心,由 Spring 注入 */
    private final StrategyRegistry registry;
    public StrategyDispatcher(StrategyRegistry registry) {
        this.registry = registry;
    }
    /**
     * 分派策略:根据组合(Combination)匹配最合适的策略实现
     */
    public Strategy dispatch(Combination combination) {
        // 1️⃣ 获取所有匹配当前组合的策略
        List matched = registry.getStrategies().stream()
                .filter(rs -> matches(rs.getAnnotation(), combination))
                .collect(Collectors.toList());
        System.out.println("[StrategyDispatcher] 组合 " + combination + " 匹配策略数量: " + matched.size());
        // 2️⃣ 无匹配策略则尝试默认策略
        if (matched.isEmpty()) {
            return findDefaultStrategy().orElseThrow(
                    () -> new RuntimeException("No matching strategy and no default strategy found for: " + combination)
            );
        }
        // 打印匹配详情
        matched.forEach(s -> System.out.println(" -> 匹配到: " + s.getInstance().getClass().getSimpleName()
                + " specificity=" + specificity(s.getAnnotation())));
        // 3️⃣ 检查是否存在多个“等价”策略(即规则冲突)
        if (matched.size() > 1) {
            matched.sort(Comparator.comparingInt(
                    (StrategyRegistry.RegisteredStrategy rs) -> specificity(rs.getAnnotation())).reversed()
            );
            int top = specificity(matched.get(0).getAnnotation());
            int next = specificity(matched.get(1).getAnnotation());
            if (top == next) {
                throw new IllegalStateException("存在策略冲突!匹配到多个等价策略: "
                        + matched.stream()
                        .map(s -> s.getInstance().getClass().getSimpleName())
                        .collect(Collectors.joining(", ")));
            }
        }
        // 4️⃣ 返回“最具体”的策略(规则约束最多者优先)
        return matched.get(0).getInstance();
    }
    /**
     * 判断注解定义的规则是否与当前组合匹配
     * - 若注解未指定该维度(数组为空),视为“通配”
     * - 若注解指定了,则必须完全匹配
     */
    private boolean matches(StrategyFor anno, Combination c) {
        if (anno == null || c == null) return false;
        if (anno.a().length > 0 && Arrays.stream(anno.a()).noneMatch(x -> x == c.getA())) return false;
        if (anno.b().length > 0 && Arrays.stream(anno.b()).noneMatch(x -> x == c.getB())) return false;
        if (anno.c().length > 0 && Arrays.stream(anno.c()).noneMatch(x -> x == c.getC())) return false;
        if (anno.d().length > 0 && Arrays.stream(anno.d()).noneMatch(x -> x == c.getD())) return false;
        return true;
    }
    /**
     * 计算策略“具体度”:
     * 指定枚举值越多,代表策略越具体(优先级越高)
     */
    private int specificity(StrategyFor anno) {
        if (anno == null) return 0;
        return (anno.a() == null ? 0 : anno.a().length)
                + (anno.b() == null ? 0 : anno.b().length)
                + (anno.c() == null ? 0 : anno.c().length)
                + (anno.d() == null ? 0 : anno.d().length);
    }
    /**
     * 从注册中心中查找默认策略(DefaultStrategy)
     * 实际项目中可改为通过注解或配置文件标识默认策略
     */
    private Optional findDefaultStrategy() {
        return registry.getStrategies().stream()
                .map(StrategyRegistry.RegisteredStrategy::getInstance)
                .filter(s -> s.getClass().getSimpleName().equals("DefaultStrategy"))
                .findFirst();
    }
}

StrategyDispatcher 是整个「策略组合系统」的核心控制器。它的职责就像调度中心,接收业务输入(A/B/C/D 组合),然后根据注册器提供的策略信息,智能地挑选出最合适的策略并执行

功能点说明
动态匹配依据注解匹配当前组合条件
具体优先指定条件越多的策略,优先级越高
冲突检测多个策略规则重复时抛出异常
默认兜底无匹配策略时自动启用 DefaultStrategy
日志可观测打印匹配过程、策略选择与具体度,便于调试

设计亮点:

  • 实现了策略体系的“智能分派”;

  • 支持多维度组合匹配;

  • 保持策略扩展与分派逻辑解耦;

  • 可通过注解灵活控制策略适配范围。

(六)启动测试与校验

通过 StrategyDispatcherSpringTest 集成测试方式验证策略分派器 StrategyDispatcher 的实际行为。模拟不同的业务组合(Combination),确保分派逻辑能够正确命中对应策略或回退默认策略。

package org.zyf.javabasic.designpatterns.strategy.tiktok.base.biz;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.core.dispatcher.StrategyDispatcher;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.AType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.BType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.CType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.enums.DType;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.Strategy;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.impl.DefaultStrategy;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.impl.StrategyAlpha;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.strategy.impl.StrategyC2D4;
import org.zyf.javabasic.designpatterns.strategy.tiktok.base.types.Combination;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertTrue;
/**
 * @program: zyfboot-javabasic
 * @description: 业务测试(SpringBootTest)
 * @author: zhangyanfeng
 * @create: 2025-11-02 19:54
 **/
@RunWith(SpringRunner.class)
@SpringBootTest
public class StrategyDispatcherSpringTest {
    @Autowired
    private StrategyDispatcher dispatcher;
    @Test
    public void testAlphaMatch() {
        Combination combo = new Combination(AType.A1, BType.B2, CType.C1, DType.D3);
        Strategy strategy = dispatcher.dispatch(combo);
        strategy.execute(combo);
        assertTrue(strategy instanceof StrategyAlpha);
    }
    @Test
    public void testC2D4Match() {
        Combination combo = new Combination(AType.A2, BType.B3, CType.C2, DType.D4);
        Strategy strategy = dispatcher.dispatch(combo);
        strategy.execute(combo);
        assertTrue(strategy instanceof StrategyC2D4);
    }
    @Test
    public void testDefaultMatch() {
        Combination combo = new Combination(AType.A2, BType.B3, CType.C1, DType.D2);
        Strategy strategy = dispatcher.dispatch(combo);
        strategy.execute(combo);
        assertTrue(strategy instanceof DefaultStrategy);
    }
    @Test
    public void testAll48Combinations() {
        List results = new ArrayList<>();
        // 遍历所有组合
        for (AType a : AType.values()) {
            for (BType b : BType.values()) {
                for (CType c : CType.values()) {
                    for (DType d : DType.values()) {
                        // 构造组合对象
                        Combination combo = new org.zyf.javabasic.designpatterns.strategy.tiktok.base.types.Combination(a, b, c, d);
                        // 分派策略
                        Strategy strategy = dispatcher.dispatch(combo);
                        // 记录结果
                        String strategyName = strategy == null ? "null" : strategy.getClass().getSimpleName();
                        results.add(String.format("%s => %s", combo, strategyName));
                    }
                }
            }
        }
        // 输出结果
        results.forEach(System.out::println);
        // 简单验证默认策略是否存在
        boolean defaultUsed = results.stream().anyMatch(r -> r.endsWith(DefaultStrategy.class.getSimpleName()));
        assert defaultUsed : "至少有组合命中默认策略";
    }
}

1. 测试目标与说明

测试方法输入组合期望命中策略说明
testAlphaMatch()(A1, B2, C1, D3)StrategyAlpha验证多维度精确匹配策略分派是否正确
testC2D4Match()(A2, B3, C2, D4)StrategyC2D4检查特定 C/D 组合策略的命中逻辑
testDefaultMatch()(A2, B3, C1, D2)DefaultStrategy测试无匹配场景下的默认策略回退机制

2. 验证说明

为了方便我们直接选取testAlphaMatch()说明如下:

五、总结:策略组合系统的魅力

面对用户类型、渠道、场景、环境这些多维组合,如果仍然依赖 if-else,代码很容易变成一团乱麻,逻辑一多就炸掉。而使用“组合 + 注解 + 分派器”的方式,我们把复杂逻辑抽象出来,系统可以自动根据输入选择最合适的策略,从而让复杂问题变得清晰可控。

新增策略也变得非常简单,只需写一个策略类,加上注解就能被系统识别,无需修改核心逻辑,也不用担心破坏已有功能。当多个策略匹配时,分派器会根据“具体度”自动判断优先级,同时检测策略冲突,避免重复或覆盖问题。而即便某个组合没有策略覆盖,默认策略也会顶上,保证系统不会出错。

更棒的是,这套系统经过了全面测试,可以遍历所有 48 种组合,确保每种情况都有对应策略,并且在匹配过程中打印日志,方便问题定位和调试。整个架构不仅适用于推荐、广告、风控等业务场景,还具有高度的复用性和可扩展性——即便未来新增维度或枚举值,核心逻辑几乎无需改动,系统自然就能支持。

用一句话总结就是:通过“组合 + 注解 + 分派器”,我们把复杂业务逻辑变得可维护、可扩展,而且更稳健,再也不用被策略乘法爆炸吓到。

posted @ 2025-11-29 19:17  yangykaifa  阅读(9)  评论(0)    收藏  举报