责任树模式

引言

前面章节我们分别讲了责任链模式与策略模式,没有看的小伙伴可以点击下面传送门查看:
责任链模式

策略模式

通过上面学习,我们知道责任链模式将请求发送者与多个处理者之间进行解耦,不同处理者的handler之间用类似链表的形式进行链接。策略模式则是针对某一个问题,可能有多种解决策略的情况下,并用不同的类来分别封装。那么有没有一种情形,既存在多个处理者,同时每个处理者又有多种解决策略呢? 其实这种 责任链模式+策略模式 的结合,就是今天我们要讲的责任树模式。

模式的定义与特点

责任链模式

责任链模式

策略模式

在这里插入图片描述

责任树模式

这个框架由一个 Router 和 Handler 组成:

  • Router 是一个抽象类,负责定义如何路由到下游的多个子节点;
  • Handler 是接口,负责实现每个节点的业务逻辑。

在这里插入图片描述

从图中我们可以看出以下几个要点:

  1. 除了根节点(入口)外,每个节点都实现了 Handler 接口。根节点只继承 Router 抽象类;
  2. 所有叶子节点只实现 Handler 接口而无需继承 Router 抽象类(无需再向下委托);
  3. 除了根节点和叶子节点外的其他节点,都是上一层的 Handler,同时是下一层的 Router;

模式的实现

  • AbstractStrategyRouter 抽象类
/**
 * 通用的“策略树“框架,通过树形结构实现分发与委托,每层通过指定的参数进行向下分发委托,直到达到最终的执行者。
 * 该框架包含两个类:{@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 层不同策略的实现
 *   +---+  +---+  +---+  +---+
 */
@Component
public abstract class AbstractStrategyRouter<T, R> {

    /**
     * 策略映射器,根据指定的入参路由到对应的策略处理者。
     *
     * @param <T> 策略的入参类型
     * @param <R> 策略的返回值类型
     */
    public interface StrategyMapper<T, R> {
        /**
         * 根据入参获取到对应的策略处理者。可通过 if-else 实现,也可通过 Map 实现。
         *
         * @param param 入参
         * @return 策略处理者
         */
        StrategyHandler<T, R> get(T param);
    }

    private StrategyMapper<T, R> strategyMapper;

    /**
     * 类初始化时注册分发策略 Mapper
     */
    @PostConstruct
    private void abstractInit() {
        strategyMapper = registerStrategyMapper();
        Objects.requireNonNull(strategyMapper, "strategyMapper cannot be null");
    }

    @Getter
    @Setter
    @SuppressWarnings("unchecked")
    private StrategyHandler<T, R> defaultStrategyHandler = StrategyHandler.DEFAULT;

    /**
     * 执行策略,框架会自动根据策略分发至下游的 Handler 进行处理
     *
     * @param param 入参
     * @return 下游执行者给出的返回值
     */
    public R applyStrategy(T param) {
        final StrategyHandler<T, R> strategyHandler = strategyMapper.get(param);
        if (strategyHandler != null) {
            return strategyHandler.apply(param);
        }

        return defaultStrategyHandler.apply(param);
    }

    /**
     * 抽象方法,需要子类实现策略的分发逻辑
     *
     * @return 分发逻辑 Mapper 对象
     */
    protected abstract StrategyMapper<T, R> registerStrategyMapper();
}

继承 AbstractStrategyRouter<T, R> 抽象类只需要实现 protected abstract StrategyMapper<T, R> registerStrategyMapper(); 抽象方法即可,在该方法中实现其不同子节点的路由逻辑。

如果子节点路由逻辑比较简单,可以直接通过 if-else 进行分发。当然如果为了更好地性能、适应更复杂的分发逻辑也可以使用 Map 等保存映射。

对于实现了该抽象类的 Router 节点,只需要调用其 public R applyStrategy(T param) 方法即可获取该节点的期望输出。框架会自动根据定义的路由逻辑将 param 传递到对应的子节点,再由子节点不断向下分发直到叶子节点或可以给出业务输出的一层。这个过程有点类似递归或者分治的思想。

  • StrategyHandler 接口
public interface StrategyHandler<T, R> {

    @SuppressWarnings("rawtypes")
    StrategyHandler DEFAULT = t -> null;

    /**
     * apply strategy
     *
     * @param param
     * @return
     */
    R apply(T param);
}

除了根节点外,都要实现 StrategyHandler<T, R> 接口。如果是叶子节点,由于不需要再向下委托,因此不再需要同时继承 AbstractStrategyRouter<T, R> 抽象类,只需要在 R apply(T param); 中实现业务逻辑即可。

对于其他责任树中的中间层节点,都需要同时继承 Router 抽象类和实现 Handler 接口,在 R apply(T param); 方法中首先进行一定异常入参拦截,遵循 fail-fast 原则,避免将这一层可以拦截的错误传递到下一层,同时也要避免「越权」做非本层职责的拦截校验,避免产生耦合,为后面业务拓展挖坑。在拦截逻辑后直接调用本身 Router 的 public R applyStrategy(T param) 方法路由给下游节点即可。

参考:
https://developer.aliyun.com/article/767754?spm=a2c6h.12873581.0.0.2e2c142cKjLBtn&groupCode=idlefish

总结:
觉得有用的客官可以点赞、关注下!感谢支持🙏谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值