package com.muyu.data.basics;

/**
 * 策略路由抽象类
 * @Author WangXin
 * @Data 2024/10/4
 * @Version 1.0.0
 * 通用的“策略树“框架，通过树形结构实现分发与委托，每层通过指定的参数进行向下分发委托，直到达到最终的执行者。
 * 该框架包含两个类：{@code StrategyHandler} 和 {@code AbstractStrategyRouter}
 * 其中：通过实现 {@code AbstractStrategyRouter} 抽象类完成对策略的分发，
 * 实现 {@code StrategyHandler} 接口来对策略进行实现。
 * 像是第二层 A、B 这样的节点，既是 Root 节点的策略实现者也是策略A1、A2、B1、B2 的分发者，这样的节点只需要
 * 同时继承 {@code StrategyHandler} 和实现 {@code AbstractStrategyRouter} 接口就可以了。
 *
 * <pre>
 *           +---------+
 *           |  Root   |   ----------- 第 1 层策略入口
 *           +---------+
 *            /       \  ------------- 根据入参 P1 进行策略分发
 *           /         \
 *     +------+      +------+
 *     |  A   |      |  B   |  ------- 第 2 层不同策略的实现
 *     +------+      +------+
 *       /  \          /  \  --------- 根据入参 P2 进行策略分发
 *      /    \        /    \
 *   +---+  +---+  +---+  +---+
 *   |A1 |  |A2 |  |B1 |  |B2 |  ----- 第 3 层不同策略的实现
 *   +---+  +---+  +---+  +---+
 *
 * </pre>
 *
 */
public abstract class EventStrategyRouter<T, R> {

    /**
     * 策略映射器, 指定入参与出参以决定策略处理者
     * @param <T>   策略入参
     * @param <R>   策略出参
     */
    public interface StrategyMapper<T,R>{
        // 通过入参获取对应策略处理方法,使用Map实现
        EventStrategyHandler<T,R> getHandler(T param);
    }

    /**
     * 选择下级策略
     * @return
     */
    protected abstract StrategyMapper<T,R> registerStrategy();

    /**
     * 默认策略处理者
     */
    @SuppressWarnings("unchecked")
    private EventStrategyHandler<T,R> defaultStrategyHandler = EventStrategyHandler.DEFAULT;


    /**
     * 选择策略处理者
     * @param param 入参
     * @return 策略处理结果
     */
    public R applyStrategy(T param) {
        StrategyMapper<T, R> trStrategyMapper = registerStrategy();
        if (trStrategyMapper == null) {
            return defaultStrategyHandler.apply(param);
        }
        final EventStrategyHandler<T,R> strategyHandler = trStrategyMapper.getHandler(param);
        if (strategyHandler != null) {
            return strategyHandler.apply(param);
        }
        // 使用默认策略处理者
        return defaultStrategyHandler.apply(param);
    }

}
