鏈式多分支規則樹模型的應用

?目錄

開始調用

初始化?


歡迎關注我的博客!26屆java選手,一起加油💘💦👨?🎓😄😂

引入

最近在學習一個項目中的鏈式多分枝規則樹模型的使用,模型如下:

如圖所示:

這是一種?鏈式多分支規則樹模型?設計模式,核心是通過功能節點自主決策后續流程執行鏈路,相比責任鏈模式,它允許更靈活的分支擴展,每個節點像 “決策者” 一樣根據規則選擇下一步走向。以下是核心組件拆解:

StrategyMapper、StrategyHandler、AbstractStrategyRouter定義在type層,與業務層隔離,然后將DefaultActivityStrategyFactory、AbstractGroupBuyMarketSupport與各節點定義在業務層進行業務邏輯處理。

  • 策略映射器(StrategyMapper)與策略處理器(StrategyHandler)
    實現抽象類?AbstractStrategyRouter,前者負責策略映射(如定義不同場景對應規則),后者處理具體策略邏輯(如執行規則計算)。
  • 策略路由抽象類(AbstractStrategyRouter)
    定義路由規則的抽象框架,規范策略映射、處理的通用邏輯,是整個流程的 “規則模板”。
  • 策略工廠(DefaultActivityStrategyFactory)
    作為 “對象制造工廠”,負責創建拼團活動相關的策略實例,確保策略對象的統一管理與創建。
  • 功能服務支撐類(AbstractGroupBuyMarketSupport)
    提供底層通用服務(如數據校驗、基礎計算),像 “后勤保障”,供上層節點流程調用。
  • 節點體系(RootNode、SwitchRoot 等)
    • 根節點(RootNode):流程起點,類似 “入口”。
    • 開關節點(SwitchRoot):核心決策點,根據條件(如用戶類型、活動規則)選擇分支(走向其他節點或默認分支)。
    • 營銷節點(MarketNode):處理營銷相關邏輯(如優惠計算)。
    • 結尾節點(EndNode):流程終點,標志鏈路結束。

開始調用

    @Resourceprivate DefaultActivityStrategyFactory defaultActivityStrategyFactory;@Overridepublic TrialBalanceEntity indexMarketTrial(MarketProductEntity marketProductEntity) throws Exception {// 獲取執行策略StrategyHandler<MarketProductEntity, DefaultActivityStrategyFactory.DynamicContext, TrialBalanceEntity> strategyHandler = defaultActivityStrategyFactory.strategyHandler();// 受理試算操作return strategyHandler.apply(marketProductEntity, new DefaultActivityStrategyFactory.DynamicContext());}

初始化

起始點為DefaultActivityStrategyFactory 策略工廠 ,返回了rootNode給我們,也就是此時的 strategyHandler是rootNode類型的,如下:

@Service
public class DefaultActivityStrategyFactory {private final RootNode rootNode;public DefaultActivityStrategyFactory(RootNode rootNode) {this.rootNode = rootNode;}public StrategyHandler<MarketProductEntity, DynamicContext, TrialBalanceEntity> strategyHandler() {return rootNode;}@Data@Builder@AllArgsConstructor@NoArgsConstructorpublic static class DynamicContext {// 拼團活動營銷配置值對象private GroupBuyActivityDiscountVO groupBuyActivityDiscountVO;// 商品信息private SkuVO skuVO;// 折扣金額private BigDecimal deductionPrice;// 支付金額private BigDecimal payPrice;// 活動可見性限制private boolean visible;// 活動private boolean enable;}}

執行流程

// 受理試算操作return strategyHandler.apply(marketProductEntity, new DefaultActivityStrategyFactory.DynamicContext());

rootNode繼承自AbstractGroupBuyMarketSupport——功能服務支撐類,AbstractGroupBuyMarketSupport又繼承自AbstractMultiThreadStrategyRouter——策略路由抽象類,就會去執行下面這里的apply方法,

public abstract class AbstractMultiThreadStrategyRouter<T, D, R> implements StrategyMapper<T, D, R>, StrategyHandler<T, D, R> {@Getter@Setterprotected 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);}@Overridepublic 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;}

會先去AbstractGroupBuyMarketSupport看看有沒有重寫multiThread和doApply方法,

public abstract class AbstractGroupBuyMarketSupport<MarketProductEntity, DynamicContext, TrialBalanceEntity> extends AbstractMultiThreadStrategyRouter<cn.bugstack.domain.activity.model.entity.MarketProductEntity, DefaultActivityStrategyFactory.DynamicContext, cn.bugstack.domain.activity.model.entity.TrialBalanceEntity> {protected long timeout = 500;@Resourceprotected IActivityRepository repository;@Overrideprotected void multiThread(cn.bugstack.domain.activity.model.entity.MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws ExecutionException, InterruptedException, TimeoutException {// 缺省的方法}}

當我們的rootNode不想用到多線程加載數據的時候就沒有重寫這個方法,為空,但是rootNode重寫了doApply方法,也就是在這里處理rootNode想要處理的業務,

@Slf4j
@Service
public class RootNode extends AbstractGroupBuyMarketSupport<MarketProductEntity, DefaultActivityStrategyFactory.DynamicContext, TrialBalanceEntity> {@Resourceprivate SwitchNode switchNode;@Overrideprotected TrialBalanceEntity doApply(MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws Exception {log.info("商品查詢試算服務-RootNode userId:{} requestParameter:{}", requestParameter.getUserId(), JSON.toJSONString(requestParameter));// 參數判斷if (StringUtils.isBlank(requestParameter.getUserId()) || StringUtils.isBlank(requestParameter.getGoodsId()) ||StringUtils.isBlank(requestParameter.getSource()) || StringUtils.isBlank(requestParameter.getChannel())) {throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());}return router(requestParameter, dynamicContext);}@Overridepublic StrategyHandler<MarketProductEntity, DefaultActivityStrategyFactory.DynamicContext, TrialBalanceEntity> get(MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws Exception {return switchNode;}}

執行完doApply方法,就執行return router()方法,這里帶上請求參數和上下文對象,router方法在AbstractMultiThreadStrategyRouter類中,負責流轉節點

 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);}

這里調用的get是StrategyMapper——策略映射器的get方法,因為當前對象是rootNode,如果rootNode實現了get就會回到rootNode的get中

public interface StrategyMapper<T, D, R> {/*** 獲取待執行策略** @param requestParameter 入參* @param dynamicContext   上下文* @return 返參* @throws Exception 異常*/StrategyHandler<T, D, R> get(T requestParameter, D dynamicContext) throws Exception;}

回到rootNode,這里重寫了get,也就是返回我們需要從rootNode去往的下一個節點

public class RootNode extends AbstractGroupBuyMarketSupport<MarketProductEntity, DefaultActivityStrategyFactory.DynamicContext, TrialBalanceEntity> {@Resourceprivate SwitchNode switchNode;@Overrideprotected TrialBalanceEntity doApply(MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws Exception {log.info("拼團商品查詢試算服務-RootNode userId:{} requestParameter:{}", requestParameter.getUserId(), JSON.toJSONString(requestParameter));// 參數判斷if (StringUtils.isBlank(requestParameter.getUserId()) || StringUtils.isBlank(requestParameter.getGoodsId()) ||StringUtils.isBlank(requestParameter.getSource()) || StringUtils.isBlank(requestParameter.getChannel())) {throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());}return router(requestParameter, dynamicContext);}@Overridepublic StrategyHandler<MarketProductEntity, DefaultActivityStrategyFactory.DynamicContext, TrialBalanceEntity> get(MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws Exception {return switchNode;}}

這里會返回switchNode給AbstractMultiThreadStrategyRouter,此時會執行switchNode的apply方法。

    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);}

與上述過程一樣,如果switchNode實現了apply中的方法,就會執行,如果沒有實現,就不會執行。再次執行doApply后就會再執行router,然后執行switch的get,這里返回了market Node,就會繼續往下,以此類推的執行下去,

@Slf4j
@Service
public class SwitchNode extends AbstractGroupBuyMarketSupport<MarketProductEntity, DefaultActivityStrategyFactory.DynamicContext, TrialBalanceEntity> {//業務邏輯return router(requestParameter, dynamicContext);}@Overridepublic StrategyHandler<MarketProductEntity, DefaultActivityStrategyFactory.DynamicContext, TrialBalanceEntity> get(MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws Exception {return marketNode;}}

MarketNode,在這里我們重寫MultiThread方法,使用FutureTask異步查詢數據后放入上下文,然后在DoApplay中還可以獲取到上下文的數據進行業務處理,處理完畢后在此處還能按照業務進入下一個節點或者返回錯誤節點。

@Slf4j
@Service
public class MarketNode extends AbstractGroupBuyMarketSupport<MarketProductEntity, DefaultActivityStrategyFactory.DynamicContext, TrialBalanceEntity> {@Resourceprivate ErrorNode errorNode;@Resourceprivate TagNode tagNode;@Overrideprotected void multiThread(MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws ExecutionException, InterruptedException, TimeoutException {// 異步查詢活動配置// 異步查詢商品信息 - 在實際生產中,商品有同步庫或者調用接口查詢。這里暫時使用DB方式查詢。// 寫入上下文 - 對于一些復雜場景,獲取數據的操作,有時候會在下N個節點獲取,這樣前置查詢數據,可以提高接口響應效率}@Overridepublic TrialBalanceEntity doApply(MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws Exception {// 獲取上面查詢得到數據的上下文數據// 執行業務,繼續放入上下文return router(requestParameter, dynamicContext);}@Overridepublic StrategyHandler<MarketProductEntity, DefaultActivityStrategyFactory.DynamicContext, TrialBalanceEntity> get(MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws Exception {//走異常節點if (null == dynamicContext.getGroupBuyActivityDiscountVO() || null == dynamicContext.getSkuVO() || null == dynamicContext.getDeductionPrice()) {return errorNode;}return tagNode;}}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/76330.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/76330.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/76330.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

GitLab之搭建(Building GitLab)

GitLab之搭建 “ 在企業開發過程中&#xff0c;GitLab憑借其強大的版本管理、CI/CD集成和項目管理功能&#xff0c;成為許多團隊的首選工具。本文將探討GitLab的基礎介紹、搭建過程、權限管理、代碼審查以及團隊知識管理等方面。通過詳細的步驟和實用的技巧&#xff0c;旨在幫…

藍橋杯 小藍的操作(一維差分)

問題描述 一個數組 aa 中共包含 nn 個數&#xff0c;問最少多少次操作&#xff0c;可以讓 aa 數組所有數都變成 11 。 操作的內容是&#xff1a;每次操作可以任選一個區間使得區間內的所有數字減 11 。 數據保證一定有解。 輸入格式 第一行一個整數 nn 表示有 nn 個整數。 …

C# net CMS相關開源軟件 技術選型 可行性分析

C# net CMS相關開源軟件 技術選型 可行性分析 OrchardCMS(微軟主導) https://github.com/OrchardCMS/OrchardCore https://docs.orchardcore.net/en/latest/ BSD Umbraco-CMS&#xff08;丹麥&#xff09; https://github.com/umbraco/Umbraco-CMS https://docs.umbraco.com/…

程序化廣告行業(77/89):融資、并購與上市全景洞察

程序化廣告行業&#xff08;77/89&#xff09;&#xff1a;融資、并購與上市全景洞察 大家好呀&#xff01;一直以來&#xff0c;我都希望能和大家一起在技術知識的海洋里暢游、學習進步。前面我們已經了解了程序化廣告行業的發展態勢、PC端和移動端投放差異以及行業融資的大致…

【解決方法】VMware 此平臺不支持虛擬化Intel VT-x/EPT

目錄 1. 引言2. 問題描述3. 解決方法3.1 方法一&#xff08;臨時&#xff09;3.2 方法二&#xff08;此方法非常離譜&#xff0c;永久有效&#xff09; 4. &#x1f911;鼓勵一下5. 求關注6. 我的其他文章推薦 1. 引言 收集同學們遇到的各種VMware安裝、使用過程中遇到的問題&a…

項目學習總結001

1. 策略模式和工廠模式 https://mp.weixin.qq.com/s/RG-h7r69JyKUlBZylJJIFQ 在軟件開發中也常常遇到類似的情況&#xff0c;實現某一個功能有多個途徑&#xff0c;此時可以使用一種設計模式來使得系統可以靈活地選擇解決途徑&#xff0c;也能夠方便地增加新的解決途徑。這就是…

OpenHarmony 5.0版本視頻硬件編解碼適配

一、簡介 Codec HDI&#xff08;Hardware Device Interface&#xff09;對上層媒體服務提供視頻編解碼的驅動能力接口&#xff0c;主要功能有獲取組件編解碼能力&#xff0c;創建、銷毀編解碼器對象&#xff0c;啟停編解碼器操作&#xff0c;編解碼處理等。 Codec HDI 2.0接口…

深度解析基于 Web Search MCP的Deep Research 實現邏輯

寫在前面 大型語言模型(LLM)已成為我們獲取信息、生成內容的重要工具。但它們的知識大多截止于訓練數據的時間點,對于需要實時信息、跨領域知識整合、多角度觀點比較的深度研究 (Deep Research) 任務,它們往往力有不逮。如何讓 LLM 突破自身知識的局限,像人類研究員一樣,…

鴻蒙案例---生肖抽卡

案例源碼&#xff1a; Zodiac_cards: 鴻蒙生肖抽獎卡片 效果演示 初始布局 1. Badge 角標組件 此處為語雀內容卡片&#xff0c;點擊鏈接查看&#xff1a;https://www.yuque.com/kevin-nzthp/lvl039/rccg0o4pkp3v6nua 2. Grid 布局 // 定義接口 interface ImageCount {url:…

基于RV1126開發板實現自學習圖像分類方案

1. 方案簡介 自學習&#xff1a;在識別前對物體圖片進行模型學習&#xff0c;訓練完成后通過算法分類得出圖像的模型ID。 方案設計邏輯流程圖&#xff0c;方案代碼分為分為兩個業務流程&#xff0c;主體代碼負責抓取、合成圖像&#xff0c;算法代碼負責訓練和檢測功能。 2. 快速…

cat命令查看文件行數

在Linux和Unix-like操作系統中&#xff0c;cat命令主要用于查看文件內容&#xff0c;而不是直接用來查看文件行數。如果你想要查看一個文件的行數&#xff0c;可以使用以下幾種方法&#xff1a; 方法1&#xff1a;使用wc命令 wc&#xff08;word count&#xff09;命令可以用…

git清理已經刪除的遠程分支

目錄 命令作用 使用場景 示例流程 注意事項 常見問題 git remote update origin --prune git remote update origin --prune 是一個 Git 命令&#xff0c;用于 更新本地遠程跟蹤分支 并 清理&#xff08;刪除&#xff09;本地已失效的遠程分支引用。以下是詳細分解&#…

NLP高頻面試題(四十)——什么是 BitFit?

BitFit(Bias-term Fine-tuning)是一種參數高效的微調方法,專注于在預訓練模型中僅調整偏置項(bias term),而將其他參數保持不變。這種方法在自然語言處理領域,尤其是在中小規模數據集上,展現出了與全量微調相媲美的性能,同時顯著減少了計算資源的消耗。 什么是 BitFi…

Java-servlet(完結篇)過濾器亂碼解決與監聽器

Java-servlet&#xff08;完結篇&#xff09;過濾器亂碼解決與監聽器 前言一、過濾器亂碼解決二、監聽器1. HttpSessionListener2. ServletContextListener3. ServletRequestListener 三、監聽器的使用場景Java-servlet 結語 前言 在之前的 Java Servlet 學習中&#xff0c;我…

為了避免unboundLocalError和為什么X的值一直不變呢?

## 1.為了避免unboundLocalError 發生unboundLocalError&#xff01; def generate_integer(level):if level 1:X randint(1,9)return X這里出錯的原因在于&#xff0c;一旦if 后面的條件沒有成立&#xff0c;然后X根本沒出生&#xff0c;然后你去使用它&#xff0c;這是有…

opencv-python基礎

一.opencv-python簡述 其使用Numpy&#xff0c;所有OpenCV數組結構都轉換為Numpy數組&#xff0c;是一個高度優化的數據庫操作庫。 二.環境安裝 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python 三.基本概念 - 像素是圖像的基本單元&#xff0c;每個…

ReentrantLock 實現公平鎖和非公平鎖的原理!

&#x1f31f;我的其他文章也講解的比較有趣&#x1f601;&#xff0c;如果喜歡博主的講解方式&#xff0c;可以多多支持一下&#xff0c;感謝&#x1f917;&#xff01; &#x1f31f;了解 ThreadLocal請看&#xff1a; ThreadLocal有趣講解&#xff0c;小白也能聽懂&#xff…

NLP高頻面試題(四十一)——什么是 IA3 微調?

隨著大型語言模型的廣泛應用,如何高效地將這些模型適配到特定任務中,成為了研究和工程實踐中的重要課題。IA3(Infused Adapter by Adding and Adjusting)微調技術,作為參數高效微調的一種新穎方法,提供了在保持模型性能的同時,顯著減少可訓練參數數量的解決方案。 IA3 …

swift菜鳥教程14(閉包)

一個樸實無華的目錄 今日學習內容&#xff1a;1.Swift 閉包1.1閉包定義1.2閉包實例1.3閉包表達式1.3.1sorted 方法&#xff1a;據您提供的用于排序的閉包函數將已知類型數組中的值進行排序。1.3.2參數名稱縮寫&#xff1a;直接通過$0,$1,$2來順序調用閉包的參數。1.3.3運算符函…

藍橋杯-藍橋幼兒園(Java-并查集)

并查集的核心思想 并查集主要由兩個操作構成&#xff1a; Find&#xff1a;查找某個元素所在集合的根節點。并查集的特點是&#xff0c;每個元素都指向它自己的父節點&#xff0c;根節點的父節點指向它自己。查找過程中可以通過路徑壓縮來加速后續的查找操作&#xff0c;即將路…