返回

策略路由框架

如何把 if-else 更优雅地写出来

责任树模型

策略路由框架详解

这个目录包含了一个精心设计的策略路由框架,它是整个团购市场系统的核心设计模式基础。我将从接口到实现,详细讲解每个组件的功能和设计思想。

1. 整体架构概览

此框架采用了分层设计,从底层接口到高级抽象类,形成了一个完整的策略路由体系:

1
2
3
4
5
6
7
StrategyHandler (基础策略处理接口)
StrategyMapper (策略映射器接口)
AbstractStrategyRouter (基础策略路由抽象类)
AbstractMultiThreadStrategyRouter (多线程策略路由抽象类)

2. 基础接口层

2.1 StrategyHandler<T, D, R> - 策略处理器接口

这是整个框架的基石,定义了策略的核心执行方法:

1
2
3
4
public interface StrategyHandler<T, D, R> {
    StrategyHandler DEFAULT = (T, D) -> null;
    R apply(T requestParameter, D dynamicContext) throws Exception;
}

关键特性

  • 使用泛型 TDR 分别表示输入参数、动态上下文和返回结果
  • 定义了默认实现 DEFAULT,返回 null,用作兜底处理
  • apply 方法是策略执行的核心,接收请求参数和上下文,返回处理结果

2.2 StrategyMapper<T, D, R> - 策略映射器接口

这个接口负责根据输入参数和上下文选择合适的策略处理器:

1
2
3
public interface StrategyMapper<T, D, R> {
    StrategyHandler<T, D, R> get(T requestParameter, D dynamicContext) throws Exception;
}

关键特性

  • get 方法是策略路由的核心,决定使用哪个策略处理器
  • 通过分析输入参数和上下文,选择最适合的处理策略
  • 设计为接口便于不同的路由算法实现

3. 抽象路由层

3.1 AbstractStrategyRouter<T, D, R> - 基础策略路由器

这个抽象类将处理器和映射器结合起来,形成完整的路由功能:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public abstract class AbstractStrategyRouter<T, D, R> 
    implements StrategyMapper<T, D, R>, StrategyHandler<T, D, R> {

    @Getter @Setter
    protected StrategyHandler<T, D, R> defaultStrategyHandler = StrategyHandler.DEFAULT;

    public R router(T requestParameter, D dynamicContext) throws Exception {
        StrategyHandler<T, D, R> strategyHandler = get(requestParameter, dynamicContext);
        if(null != strategyHandler) return strategyHandler.apply(requestParameter, dynamicContext);
        return defaultStrategyHandler.apply(requestParameter, dynamicContext);
    }
}

关键特性

  • 同时实现了 StrategyMapperStrategyHandler 接口
  • 提供 defaultStrategyHandler 作为兜底策略
  • 提供 router 方法作为核心路由逻辑
  • 先使用 get 方法获取处理器,再使用 apply 方法执行处理

3.2 AbstractMultiThreadStrategyRouter<T, D, R> - 多线程策略路由器

这是对基础路由器的扩展,增加了异步数据加载能力:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public abstract class AbstractMultiThreadStrategyRouter<T, D, R> 
    implements StrategyMapper<T, D, R>, StrategyHandler<T, D, R> {
    
    // 同样拥有defaultStrategyHandler和router方法
    
    @Override
    public R apply(T requestParameter, D dynamicContext) throws Exception {
        // 异步加载数据
        multiThread(requestParameter, dynamicContext);
        // 业务流程受理
        return doApply(requestParameter, dynamicContext);
    }
    
    // 异步加载数据的抽象方法
    protected abstract void multiThread(T requestParameter, D dynamicContext) 
        throws ExecutionException, InterruptedException, TimeoutException;
    
    // 业务流程处理的抽象方法
    protected abstract R doApply(T requestParameter, D dynamicContext) throws Exception;
}

关键特性

  • 覆盖了 apply 方法,增加异步数据加载步骤
  • 将业务逻辑拆分为 multiThread(异步加载数据)和 doApply(业务处理)
  • 适用于需要并行加载多个资源的复杂业务场景
  • 支持异步编程模型,提高系统响应性

4. 设计思想和应用场景

4.1 设计思想

这个框架体现了多种高级设计思想:

  1. 泛型编程:使用泛型保证类型安全
  2. 组合优于继承:通过接口组合而非单纯继承实现功能扩展
  3. 模板方法模式:核心流程在抽象类中定义,具体步骤留给子类实现
  4. 策略模式:将不同的处理策略封装到不同的类中
  5. 责任链模式:通过路由机制构建处理链
  6. 异步编程模型:支持多线程并行处理提高性能

4.2 应用场景

这个框架特别适合以下场景:

  1. 复杂业务决策:需要根据多种因素选择处理路径
  2. 多级处理流程:业务流程有多个处理阶段,每个阶段有不同的处理逻辑
  3. 可扩展业务规则:需要频繁添加新的处理规则
  4. 高性能要求:需要并行加载多个资源以提高性能
  5. 树形决策结构:业务逻辑呈现树形结构的决策过程

5. 实际使用示例

在团购营销系统中,这个框架的使用方式:

  1. 创建具体的路由器(如 AbstractGroupBuyMarketSupport)继承 AbstractStrategyRouter
  2. 实现 get 方法,根据产品类型和上下文选择合适的处理节点
  3. 实现 apply 方法,执行当前节点的业务逻辑
  4. 创建具体的处理节点(如 RootNodeMarketNode 等)
  5. 使用工厂类 DefaultActivityStrategyFactory 初始化和管理节点

6. 框架的优势

  1. 高度解耦:每个策略的实现相互独立
  2. 易于扩展:添加新策略只需实现接口,不需修改现有代码
  3. 动态路由:根据运行时条件选择处理策略
  4. 异步支持:内置多线程异步处理能力
  5. 类型安全:泛型支持保证类型安全
  6. 兜底机制:提供默认处理器处理异常情况

7. 与经典设计模式的比较

  1. vs 传统策略模式:增加了动态路由选择,更适合复杂场景
  2. vs 责任链模式:增加了策略选择,更有结构化的处理方式
  3. vs 命令模式:增加了上下文传递,支持更复杂的业务状态

8. 性能考虑

  1. 异步处理:多线程版本支持并行加载数据
  2. 懒加载:策略可以按需创建和使用
  3. 路由缓存:可以在实现中添加路由结果缓存提高性能

总结

这个策略路由树框架是一个非常精巧的设计,它将策略模式和责任链模式的优点结合起来,再加上异步处理的能力,形成了一个功能强大、扩展性好的业务处理框架。在团购营销这样的复杂业务场景中,它能够有效地降低代码复杂度,提高系统的可维护性和可扩展性。

通过这种设计,业务逻辑可以被拆解为清晰的决策树,每个节点职责单一,便于理解和维护。而异步处理的支持则提高了系统的性能和响应能力。


策略路由树框架中的多线程实现详解

通过检索整个项目,我发现了策略路由树框架中多线程实现的全貌。这是一个精心设计的异步数据加载机制,用于提高系统性能和响应能力。下面是详细分析:

1. 多线程架构设计

1.1 核心抽象类 - AbstractMultiThreadStrategyRouter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public abstract class AbstractMultiThreadStrategyRouter<T, D, R> implements StrategyMapper<T, D, R>, StrategyHandler<T, D, R> {
    @Override
    public R apply(T requestParameter, D dynamicContext) throws Exception {
        // 异步加载数据
        multiThread(requestParameter, dynamicContext);
        // 业务流程受理
        return doApply(requestParameter, dynamicContext);
    }

    // 异步加载数据的抽象方法
    protected abstract void multiThread(T requestParameter, D dynamicContext) throws ExecutionException, InterruptedException, TimeoutException;

    // 业务流程处理的抽象方法
    protected abstract R doApply(T requestParameter, D dynamicContext) throws Exception;
}

这个抽象类是多线程实现的核心,它:

  1. 覆盖了 apply 方法,将处理流程分为两个阶段
  2. 引入了 multiThread 抽象方法用于异步数据加载
  3. 引入了 doApply 抽象方法用于业务处理
  4. 确保数据加载完成后再进行业务处理

1.2 线程池配置 - ThreadPoolConfig

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@Configuration
public class ThreadPoolConfig {
    @Bean
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties properties) {
        // 创建线程池
        return new ThreadPoolExecutor(
                properties.getCorePoolSize(),    // 核心线程数(默认20)
                properties.getMaxPoolSize(),     // 最大线程数(默认200)
                properties.getKeepAliveTime(),   // 空闲线程存活时间(默认10秒)
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(properties.getBlockQueueSize()), // 队列大小(默认5000)
                Executors.defaultThreadFactory(),
                handler);  // 拒绝策略
    }
}

项目使用了自定义的线程池配置,可通过外部参数调整:

  • 核心线程数:20
  • 最大线程数:200
  • 线程存活时间:10 秒
  • 队列大小:5000
  • 可配置的拒绝策略

2. 多线程具体实现

2.1 线程任务封装

系统使用 Callable 接口封装具体的异步任务:

  1. 查询营销配置任务
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class QueryGroupBuyActivityDiscountVOThreadTask implements Callable<GroupBuyActivityDiscountVO> {
    private final String source;
    private final String channel;
    private final IActivityRepository activityRepository;
    
    @Override
    public GroupBuyActivityDiscountVO call() throws Exception {
        return activityRepository.queryGroupBuyActivityDiscountVO(source, channel);
    }
}
  1. 查询商品信息任务
1
2
3
4
5
6
7
8
9
public class QuerySkuVOFromDBThreadTask implements Callable<SkuVO> {
    private final String goodsId;
    private final IActivityRepository activityRepository;
    
    @Override
    public SkuVO call() throws Exception {
        return activityRepository.querySkuByGoodsId(goodsId);
    }
}

2.2 异步任务执行 - MarketNode

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MarketNode extends AbstractGroupBuyMarketSupport<MarketProductEntity, DefaultActivityStrategyFactory.DynamicContext, TrialBalanceEntity> {
    @Resource
    private ThreadPoolExecutor threadPoolExecutor;
    
    @Override
    protected void multiThread(MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws ExecutionException, InterruptedException, TimeoutException {
        // 异步查询活动配置
        QueryGroupBuyActivityDiscountVOThreadTask task1 = new QueryGroupBuyActivityDiscountVOThreadTask(
            requestParameter.getSource(), requestParameter.getChannel(), repository);
        FutureTask<GroupBuyActivityDiscountVO> future1 = new FutureTask<>(task1);
        threadPoolExecutor.execute(future1);

        // 异步查询商品信息
        QuerySkuVOFromDBThreadTask task2 = new QuerySkuVOFromDBThreadTask(
            requestParameter.getGoodsId(), repository);
        FutureTask<SkuVO> future2 = new FutureTask<>(task2);
        threadPoolExecutor.execute(future2);

        // 写入上下文 - 等待所有异步任务完成
        dynamicContext.setGroupBuyActivityDiscountVO(future1.get(timeout, TimeUnit.MINUTES));
        dynamicContext.setSkuVO(future2.get(timeout, TimeUnit.MINUTES));
    }
    
    @Override
    public TrialBalanceEntity doApply(MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws Exception {
        // 使用异步加载的数据进行业务处理
        // ...
        return router(requestParameter, dynamicContext);
    }
}

这是多线程实现的核心:

  1. 注入 ThreadPoolExecutor 线程池
  2. multiThread 方法中创建并提交多个异步任务
  3. 使用 FutureTask 包装 Callable 任务
  4. 使用 future.get(timeout, TimeUnit) 等待任务完成,并设置超时时间
  5. 将异步获取的结果存入上下文 DynamicContext
  6. doApply 方法中使用这些已加载的数据进行业务处理

2.3 上下文设计 - DynamicContext

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class DynamicContext {
    // 拼团活动营销配置值对象
    private GroupBuyActivityDiscountVO groupBuyActivityDiscountVO;
    // 商品信息
    private SkuVO skuVO;
}

上下文类用于存储异步获取的数据,供后续处理使用。

3. 多线程工作流程

整个多线程处理流程如下:

  1. 请求进入:外部请求调用 apply 方法

  2. 异步数据加载

    • 创建多个线程任务(查询活动配置、商品信息等)
    • 提交到线程池并行执行
    • 等待所有任务完成并获取结果
    • 将结果存入上下文
  3. 业务处理

    • 异步数据加载完成后,执行 doApply 方法
    • 使用上下文中的数据进行业务逻辑处理
    • 继续路由到下一个节点(如 EndNode)
  4. 结果返回:返回最终处理结果

4. 多线程的优势

在这个设计中,多线程带来了几个关键优势:

  1. 性能提升:并行执行多个 IO 操作(如数据库查询),减少总体处理时间
  2. 资源优化:通过线程池管理,避免频繁创建和销毁线程
  3. 超时控制:设置任务超时时间,防止长时间阻塞
  4. 前置数据加载:提前并行加载多个节点可能需要的数据,提高系统响应性
  5. 业务解耦:数据加载与业务处理分离,使代码更清晰

5. 异常处理

多线程实现中的异常处理机制:

  1. 使用 try-catch 机制捕获异步任务中的异常
  2. 通过 Future.get() 抛出的异常传递给调用方
  3. 处理三种主要异常:
    • ExecutionException:任务执行异常
    • InterruptedException:线程中断异常
    • TimeoutException:任务超时异常

总结

这个多线程实现是策略路由树框架的重要扩展,它通过并行数据加载优化了系统性能。核心思想是:将数据加载与业务处理分离,使用异步方式并行获取多个资源,然后在所有数据准备就绪后执行业务逻辑

这种设计特别适合需要多个外部资源(数据库、外部服务等)的复杂业务场景,能够显著提高系统的响应性和吞吐量。同时,通过统一的抽象类和接口设计,使得异步逻辑能够无缝集成到现有的策略路由树框架中。

Licensed under CC BY-NC-SA 4.0
昵称
邮箱
网址
0/500
0 条评论
© 2023 - 2025 壹壹贰捌 · 821Days
共书写了 265.7k 字・共 93 篇文章 京 ICP 备 2023035941 号 - 1