设计模式——规则树模型结构
规则树模型结构分析 - 通过场景剖析其应用思路,并掌握工程实践中如何使用它。
写在前面
通过规则树模型结构可以更优雅地编写我们在项目中构建大量ifelse逻辑的场景,并且越是随着树型逻辑分支的迭代增多,规则树结构下多人协同维护的优势更加明显。
一、场景设置
当完成某些业务或功能的流程设计后,如果需要选择使用设计模式来实现流程时,常常遇到选型的问题。因为很多时候我们的流程既不是纯粹的链表也不是严格的树,介于树或者列表之间。例如
订单场景:在虚拟机申请的订单业务中,有许多必要的检查、资源分配、实施、通知等等流程,以及后期在多云厂商的环境下不同场景会有不同的实现。申请流程如下图大部分情况是链式结构,但同时存在随时拓展分支的可能性,例如检查失败节点、资源分配失败节点、实施中断节点等等异常节点。
配额场景:又或者是在某一个具体的领域中,例如配额领域中,同样有许多必要的检查、分配、扣减、返还等等流程,以及在不同来源不同类型资源下会有不同的扣减、超额等等策略。
在这些场景中,我们可能会快速判断出适合选择使用模版模式、工厂模式、策略模式等等设计模式…
但是可能会在责任链或者是规则树模式中间纠结一阵。
那么不妨试一试本文介绍的这套基于规则树模型结构实现流程驱动的模版。
二、通用模版
这套模版是基于规则树的思想而产生,但是节点驱动的方式由配置转变为了由代码控制,并且具有范式设计,可以更加泛化地应用在各种场景。先介绍三个核心部件:
策略映射器
/**
* 策略映射器
* T 入参类型
* D 上下文参数
* R 返参类型
*/
public interface StrategyMapper<T, D, R> {
// 获取待执行策略
StrategyHandler<T, D, R> get(T requestParameter, D dynamicContext) throws Exception;
}
受理策略处理
/**
* 受理策略处理
* T 入参类型
* D 上下文参数
* R 返参类型
*/
public interface StrategyHandler<T, D, R> {
StrategyHandler DEFAULT = (T, D) -> null;
R apply(T requestParameter, D dynamicContext) throws Exception;
}
策略路由抽象类
/**
* 策略路由抽象类
*/
public abstract class AbstractStrategyRouter<T, D, R> implements StrategyMapper<T, D, R>, StrategyHandler<T, D, R> {
@Getter
@Setter
protected StrategyHandler<T, D, R> defaultStrategyHandler = 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);
}
}
三、使用实例
本文以申请创建资源的简化场景为例,实现如下业务流程:
抽象的订单模块支撑类
/**
* 抽象的订单模块支撑类
*/
public abstract class AbstractOrderSupport<OrderEntity, DynamicContext, ResourceReturnEntity> extends AbstractStrategyRouter<OrderEntity, DefaultOrderStrategyFactory.DynamicContext, ResourceReturnEntity> {
@Resource
protected IOrderRepository<