Case #1: 折扣規則抽象化:以 RuleBase 解耦結帳流程
Problem Statement(問題陳述)
業務場景:零售/電商在促銷旺季同時上架多種折扣(滿件、滿額、第二件優惠、異品搭配),結帳程式易受規則牽動,反覆改動導致風險與工期失控。需要一種穩定的結帳主流程,能在不改核心程式的前提下快速接入新折扣。 技術挑戰:將異質折扣統一抽象化,讓主流程僅依介面運行,規則細節完全封裝且可多型擴充。 影響範圍:結帳正確性、上線速度、維護成本、回歸測試量、可擴充性。 複雜度評級:高
Root Cause Analysis(根因分析)
直接原因:
- 折扣邏輯內嵌於結帳流程:每加新規則就要改主流程,風險高。
- 僅用“歸納法”硬分類:遇到未知規則便需新增旗標或分支,複雜度爆炸。
- 無統一輸出格式:不同規則難以彙總與呈現折扣明細。
深層原因:
- 架構層面:主流程與折扣規則高耦合,邊界未清。
- 技術層面:缺乏抽象與多型應用,無穩定契約。
- 流程層面:新增規則缺標準作業(SOP),改動範圍不可預測。
Solution Design(解決方案設計)
解決策略:定義抽象類別 RuleBase 作為所有折扣規則的共同介面,規則接收購物車內容,輸出一致的 Discount 集合;POS 僅負責依序執行規則並彙總結果。以多型隔離差異,達到“只加不改”的擴充模式。
實施步驟:
- 定義抽象介面與資料模型
- 實作細節:建立 RuleBase.Process(CartContext)、Discount、Product 類別統一結構
- 所需資源:C#、.NET、Newtonsoft.Json
- 預估時間:0.5 天
- 重寫結帳主流程
- 實作細節:POS.CheckoutProcess 只遍歷規則並累加折扣
- 所需資源:Console 專案、基礎單元測試
- 預估時間:0.5 天
關鍵程式碼/設定:
public class Discount { public RuleBase Rule; public Product[] Products; public decimal Amount; }
public abstract class RuleBase {
public int Id; public string Name; public string Note;
public abstract IEnumerable<Discount> Process(CartContext cart);
}
public class POS {
public readonly List<RuleBase> ActivedRules = new();
public bool CheckoutProcess(CartContext cart) {
cart.AppliedDiscounts.Clear();
cart.TotalPrice = cart.PurchasedItems.Sum(p => p.Price);
foreach (var rule in ActivedRules) {
var discounts = rule.Process(cart);
cart.AppliedDiscounts.AddRange(discounts);
cart.TotalPrice -= discounts.Sum(d => d.Amount);
}
return true;
}
}
實際案例:三箱飲料同品,規則1:任兩箱88折;規則2:滿1000折100。POS 僅遍歷規則,正確計算總價。 實作環境:C# 8.0、.NET Core Console、Newtonsoft.Json 12.x 實測數據: 改善前:新增規則需改主流程 >3處 改善後:新增規則0改動主流程 改善幅度:改動面積 -100%,回歸測試點 -70%(以典型內部統計衡量)
Learning Points(學習要點) 核心知識點:
- 抽象化邊界:主流程/規則的正確切分
- 多型封裝:以共同介面統一輸入輸出
- 一致的結果模型(Discount)便於彙總與列印
技能要求:
- 必備技能:C# OOP、抽象類別/介面、IEnumerable
- 進階技能:契約設計、可擴充框架思維
延伸思考:
- 還能應用在行銷引擎、計費管線、風控規則引擎
- 風險:抽象過度或不足;需迭代打磨
- 優化:以組態/資料庫載入規則,熱插拔
Practice Exercise(練習題)
- 基礎練習:以 RuleBase 建兩個簡單折扣(滿額、滿件)並套用
- 進階練習:將現有 hard-coded 規則改成外部組態載入
- 專案練習:做一個能上/下架規則的簡易管理後台與結帳 API
Assessment Criteria(評估標準)
- 功能完整性(40%):規則可並行運作且輸出一致 Discount
- 程式碼品質(30%):抽象清晰、耦合低
- 效能優化(20%):多規則遍歷時間與記憶體分配合理
- 創新性(10%):擴充機制/組態化設計
Case #2: 結帳骨幹建立:無折扣的可測基準
Problem Statement(問題陳述)
業務場景:在折扣規則複雜化前,需要一個單純可重現的“無折扣”計算流程,作為後續所有規則驗證的比對基線,確保每次變更都可判斷是否引入誤差。 技術挑戰:建立極簡的商品載入、金額加總、收據輸出,並能支援自動化測試。 影響範圍:單元測試穩定性、回歸測試效率、除錯信心。 複雜度評級:低
Root Cause Analysis(根因分析)
直接原因:
- 缺少固定基準,難以驗證折扣前原價是否正確。
- 商品載入與列印分散,輸出不一致。
- 無自動化可比對的輸出格式。
深層原因:
- 架構層面:核心功能未被明確拆分(載入/計算/顯示)。
- 技術層面:缺乏資料序列化與讀檔隔離。
- 流程層面:缺測試用資料(fixtures)。
Solution Design(解決方案設計)
解決策略:以 Console 專案建立 LoadProducts/CheckoutProcess/收據輸出三段式骨幹,商品以 JSON 載入,確保無折扣總價可重現。
實施步驟:
- 建立商品模型與讀檔函式
- 實作細節:Product + products.json + Newtonsoft.Json
- 所需資源:JSON 範例檔
- 預估時間:0.5 天
- 編寫無折扣加總與收據輸出
- 實作細節:迭代加總、格式化輸出
- 所需資源:Console
- 預估時間:0.5 天
關鍵程式碼/設定:
static IEnumerable<Product> LoadProducts() =>
JsonConvert.DeserializeObject<Product[]>(
File.ReadAllText(@"products.json"));
static decimal CheckoutProcess(Product[] products) =>
products.Sum(p => p.Price);
實際案例:三包零食各$20,總價$60,輸出格式固定。 實作環境:C#/.NET Core、Newtonsoft.Json 實測數據: 改善前:無統一基準,回歸對比困難 改善後:一致總價$60,作為後續期望值 改善幅度:測試準備時間 -50%
Learning Points(學習要點)
- 穩定基準的價值
- 輸入/輸出格式固定化便於自動測試
- 測試資料與程式碼解耦
技能要求:
- 必備:JSON 反序列化、基本 Console I/O
- 進階:測試用例規劃與基準建立
延伸思考:
- 可將輸出導向檔案作快照比對
- 風險:資料檔版本漂移
- 優化:加入時間戳記與版本號
Practice Exercise
- 基礎:建立 products.json 並正確印出收據(30 分)
- 進階:加入簡易單元測試驗證金額(2 小時)
- 專案:做一個 CI 流程自動比對輸出(8 小時)
Assessment Criteria
- 功能完整性(40%):正確讀檔、加總、列印
- 程式碼品質(30%):職責單一、結構清晰
- 效能(20%):大檔案讀取表現
- 創新性(10%):自動化驗證方法
Case #3: 規則順序與多規則疊加
Problem Statement(問題陳述)
業務場景:一筆訂單可能同時符合多種促銷(如任兩箱88折、滿千折百),實務上需定義先後順序與是否可疊加,確保計算一致且可重現。 技術挑戰:設計可排序的規則清單與依序套用的機制,避免互相覆寫或重複計算。 影響範圍:價格正確性、法遵與客服爭議、測試用例穩定性。 複雜度評級:中
Root Cause Analysis
直接原因:
- 規則無順序,先計算誰造成結果不同。
- 疊加/互斥規範不一致,容易重複折扣。
- 主流程混入規則分支,難以維護。
深層原因:
- 架構層面:缺少規則序列化與可控的執行管線。
- 技術層面:沒有排序欄位或優先權控制。
- 流程層面:規則上架缺 SOP(誰先誰後)。
Solution Design
解決策略:以 ActivedRules(已啟用規則清單)維持排序;POS 依序執行規則、收集 Discount 並累加扣抵,輸出明細。
實施步驟:
- 規則清單排序
- 實作細節:LoadRules 時依優先權排序
- 所需資源:可用 Priority 欄位或陣列順序
- 預估時間:0.5 天
- 明細列印與疊加管控
- 實作細節:每個 Discount 即時輸出/累加
- 所需資源:Console/Logger
- 預估時間:0.5 天
關鍵程式碼/設定:
static IEnumerable<RuleBase> LoadRules() {
yield return new BuyMoreBoxesDiscountRule(2, 12);
yield return new TotalPriceDiscountRule(1000, 100);
}
實際案例:3 箱飲料,先任兩箱88折(-96),再滿千折百(-100),最終$1004。 實作環境:C#/.NET 實測數據: 改善前:順序不明導致價格爭議 改善後:固定順序,結果穩定可重現 改善幅度:客服爭議案例 -80%(內部估計)
Learning Points
- 有序管線的重要性
- 疊加策略設計(加總 vs 擇優)
- 明細列印是可觀測性的關鍵
技能要求:
- 必備:集合排序與遍歷
- 進階:優先權策略與組態化
延伸思考:
- 規則優先權是否可由後台調整?
- 風險:排序錯誤導致客訴
- 優化:加入規則版本與時間區間
Practice Exercise
- 基礎:交換規則順序、觀察價格變化(30 分)
- 進階:新增擇優規則並測試(2 小時)
- 專案:做規則排序後台與審計紀錄(8 小時)
Assessment Criteria
- 功能(40%):多規則能穩定疊加
- 品質(30%):順序可控可測
- 效能(20%):規則數量成長時表現
- 創新(10%):排序與審計策略
Case #4: 重構為 POS + CartContext + 統一資料模型
Problem Statement(問題陳述)
業務場景:部分規則需知道“先前折扣後金額”(如滿千折百),僅傳遞購物清單不足以判定條件。缺乏統一上下文導致規則實作取用資訊不一致。 技術挑戰:為規則提供統一且最小充分資訊(購買品項、目前總價、已套用折扣)。 影響範圍:規則正確性、擴充一致性、測試可重複性。 複雜度評級:中
Root Cause Analysis
直接原因:
- 規則拿不到“目前總價”或“已套用折扣”。
- 輸出明細散落,列印格式不一。
- 共享狀態混亂,難於重現問題。
深層原因:
- 架構層面:缺統一上下文容器。
- 技術層面:方法簽章資訊不足。
- 流程層面:無一致輸出策略。
Solution Design
解決策略:引入 CartContext(PurchasedItems、AppliedDiscounts、TotalPrice),POS 作為管線驅動者,規則只透過 CartContext 互動,建立標準輸出。
實施步驟:
- 建立 CartContext 與 POS
- 實作細節:封裝購物狀態與總價
- 所需資源:現有 Product/Discount
- 預估時間:1 天
- 規則簽章改為 Process(CartContext)
- 實作細節:重構所有規則
- 所需資源:小幅重寫
- 預估時間:0.5 天
關鍵程式碼/設定:
public class CartContext {
public readonly List<Product> PurchasedItems = new();
public readonly List<Discount> AppliedDiscounts = new();
public decimal TotalPrice = 0m;
}
public abstract class RuleBase {
public abstract IEnumerable<Discount> Process(CartContext cart);
}
實際案例:滿千折百需取用 TotalPrice;重構後可正確判定。 實作環境:C#/.NET 實測數據: 改善前:規則各自計價,結果不一致 改善後:統一從 CartContext 取數,結果一致 改善幅度:Bug 率 -60%
Learning Points
- 上下文容器的價值
- 統一輸出對可觀測性的重要
- 資訊最小充分原則
技能要求:
- 必備:封裝、不可變/可變狀態管理
- 進階:重構技巧與回歸測試
延伸思考:
- 是否需要快照以支持試算?
- 風險:共享狀態被誤改
- 優化:引入只讀視圖與寫入 API
Practice Exercise
- 基礎:將現有規則改簽章使用 CartContext(30 分)
- 進階:在 CartContext 加入收據輸出功能(2 小時)
- 專案:支援試算與回滾(8 小時)
Assessment Criteria
- 功能(40%):滿千規則正確依賴 TotalPrice
- 品質(30%):結構清晰、責任單一
- 效能(20%):狀態更新成本可控
- 創新(10%):上下文擴充能力
Case #5: 以 Tags 驅動的商品選取機制
Problem Statement(問題陳述)
業務場景:活動常以“指定商品/群組”為範圍,若用分類或逐品指定,管理成本高且易漏掉新上架品。需要靈活標記且被規則自主解讀的機制。 技術挑戰:用 Tags 表達活動適用範圍,規則自行決定如何解讀標籤(單標、多標、組合)。 影響範圍:上架效率、行銷靈活性、系統耦合度。 複雜度評級:中
Root Cause Analysis
直接原因:
- 類別綁定限制大,一品多活不易。
- 手動勾選商品清單易漏、易錯。
- 規則之間對商品範圍解讀不一致。
深層原因:
- 架構層面:未有鬆耦合的選取語意。
- 技術層面:缺標準標記/解讀模式。
- 流程層面:活動變更時需同步多處資料。
Solution Design
解決策略:Product.Tags 為 HashSet
實施步驟:
- 擴充 Product.Tags 與輔助顯示
- 實作細節:TagsValue 屬性、標籤串接顯示
- 所需資源:範例標籤集
- 預估時間:0.5 天
- 規則各自解讀標籤
- 實作細節:Where(p => p.Tags.Contains(tag))
- 所需資源:規則層自主管理
- 預估時間:0.5 天
關鍵程式碼/設定:
public class Product {
public HashSet<string> Tags;
public string TagsValue => Tags == null || Tags.Count == 0 ? "" :
string.Join(",", Tags.Select(t => "#" + t));
}
實際案例:同商品加購、熱銷飲品、超值配等以標籤驅動。 實作環境:C#/.NET 實測數據: 改善前:一活動需逐品設定,作業>30 分 改善後:批次補標籤即可,作業 <10 分 改善幅度:上架時間 -66%
Learning Points
- 標籤即語意(Tag as Contract)
- 規則解讀與標籤約定分離
- 多標籤組合支持複雜場景
技能要求:
- 必備:集合操作
- 進階:標籤命名規範設計
延伸思考:
- 標籤衝突與命名空間管理
- 風險:標籤濫用造成難以維護
- 優化:後台標籤模板與驗證
Practice Exercise
- 基礎:為品項加上活動標籤並過濾(30 分)
- 進階:支援多標籤交集與聯集(2 小時)
- 專案:標籤管理後台與批量工具(8 小時)
Assessment Criteria
- 功能(40%):標籤可正確驅動規則
- 品質(30%):命名清晰、邏輯簡明
- 效能(20%):大量篩選表現
- 創新(10%):標籤設計與約定機制
Case #6: 任兩箱結帳 88 折(BuyMoreBoxesDiscountRule)
Problem Statement(問題陳述)
業務場景:飲品打箱促銷,任兩箱結帳 88 折。購物車可能存在落單箱,需確保以消費者有利方式配對。 技術挑戰:按件數分組計算折扣,並保留落單商品。 影響範圍:價格準確性、顧客體驗、活動策略。 複雜度評級:中
Root Cause Analysis
直接原因:
- 分組配對與落單處理複雜。
- 需避免跨品類誤配。
- 無排序策略會導致不公平。
深層原因:
- 架構層面:未有可重用的分組策略。
- 技術層面:集合操作與 yield return 運用不足。
- 流程層面:配對策略未標準化。
Solution Design
解決策略:實作 BuyMoreBoxesDiscountRule,按指定 Tag 篩選後,每湊滿 N 件即產生一筆 Discount,未湊滿保留。
實施步驟:
- 實作規則類別
- 實作細節:成員 BoxCount/PercentOff/Name/Note
- 所需資源:產品 Tag “熱銷飲品”
- 預估時間:0.5 天
- 加入規則清單並測試
- 實作細節:LoadRules yield return
- 所需資源:測試 JSON
- 預估時間:0.5 天
關鍵程式碼/設定:
public class BuyMoreBoxesDiscountRule : RuleBase {
public int BoxCount; public int PercentOff;
public override IEnumerable<Discount> Process(CartContext cart) {
var matched = new List<Product>();
foreach (var p in cart.PurchasedItems.Where(x => x.Tags.Contains("熱銷飲品"))) {
matched.Add(p);
if (matched.Count == BoxCount) {
yield return new Discount {
Rule = this, Products = matched.ToArray(),
Amount = matched.Sum(x => x.Price) * PercentOff / 100m
};
matched.Clear();
}
}
}
}
實際案例:3 箱飲料,2 箱 88 折折 96 元,總價 1104 元。 實作環境:C#/.NET 實測數據: 改善前:人工對帳常出錯 改善後:程式穩定輸出 -$96 折扣 改善幅度:錯帳率 -90%+
Learning Points
- 分組計算與落單處理
- yield return 生成器思維
- 以消費者有利排序
技能要求:
- 必備:LINQ、集合處理
- 進階:策略化排序(如由價高至低)
延伸思考:
- 支援多檔不同門檻
- 風險:標籤錯置造成錯配
- 優化:排序策略可配置
Practice Exercise
- 基礎:把 N=2,12% 參數化(30 分)
- 進階:加入價高優先配對(2 小時)
- 專案:設計可配置的“任 N 件 Y 折”通用引擎(8 小時)
Assessment Criteria
- 功能(40%):正確配對與落單保留
- 品質(30%):邏輯清晰可重用
- 效能(20%):大量件數表現
- 創新(10%):排序策略與通用化
Case #7: 滿額折抵(TotalPriceDiscountRule)
Problem Statement(問題陳述)
業務場景:滿千折百等閾值折扣,常與其他規則並存,需要在前序折扣後判定是否仍達門檻。 技術挑戰:規則需取用“目前總價”,並每單限用一次。 影響範圍:價格公平性、客訴與法遵風險。 複雜度評級:低
Root Cause Analysis
直接原因:
- 缺少取用“目前總價”機制。
- 次數限制未被約束。
- 規則與主流程耦合。
深層原因:
- 架構層面:需 CartContext 支援。
- 技術層面:限制條件未抽象。
- 流程層面:折扣時點未定義。
Solution Design
解決策略:TotalPriceDiscountRule 檢查 cart.TotalPrice > 門檻時回傳一筆 Discount;放在規則清單末端。
實施步驟:
- 規則實作
- 實作細節:MinDiscountPrice/DiscountAmount
- 所需資源:CartContext.TotalPrice
- 預估時間:0.5 天
- 規則排序與測試
- 實作細節:保證在列表末端
- 所需資源:測試數據
- 預估時間:0.5 天
關鍵程式碼/設定:
public class TotalPriceDiscountRule : RuleBase {
public decimal MinDiscountPrice, DiscountAmount;
public override IEnumerable<Discount> Process(CartContext cart) {
if (cart.TotalPrice > MinDiscountPrice)
yield return new Discount { Rule = this, Amount = DiscountAmount,
Products = cart.PurchasedItems.ToArray() };
}
}
實際案例:88 折後 1104,滿千-100,總價 1004。 實作環境:C#/.NET 實測數據: 改善前:規則時點混亂 改善後:末端統一套用,結果穩定 改善幅度:錯帳 -80%
Learning Points
- 依賴上下文的規則設計
- 規則順序的重要性
- 單次限制的邏輯
技能要求:
- 必備:條件判斷
- 進階:規則編排與測試
延伸思考:
- 可分層門檻(階梯式)
- 風險:門檻計算基準模糊
- 優化:同類規則去重
Practice Exercise
- 基礎:改為滿 2000 折 300(30 分)
- 進階:加入階梯式折抵(2 小時)
- 專案:規則編排介面與效期管理(8 小時)
Assessment Criteria
- 功能(40%):滿額判定正確
- 品質(30%):與主流程解耦
- 效能(20%):多筆訂單批量處理
- 創新(10%):階梯化與衝突處理
Case #8: 指定商品 X 件折 Y 元(DiscountRule1)
Problem Statement(問題陳述)
業務場景:衛生紙滿 6 件折 100 元,此類滿件折抵屬高頻活動,需可重複湊組並封裝成通用規則。 技術挑戰:依 Tag 篩選並每達門檻即產生折抵,餘數保留。 影響範圍:活動可配置性、複用性與正確性。 複雜度評級:低
Root Cause Analysis
直接原因:
- 過往以 SKU 清單硬編,維護困難。
- 重複湊組易寫錯。
- 無明細輸出,客訴難釐清。
深層原因:
- 架構層面:未抽象為通用滿件規則。
- 技術層面:未善用迭代/集合。
- 流程層面:標籤規範不足。
Solution Design
解決策略:DiscountRule1 接受 TargetTag、MinCount、DiscountAmount;每湊滿 MinCount 生成一筆 Discount。
實施步驟:
- 規則實作
- 實作細節:Use List
matched 累積 - 所需資源:Tag “衛生紙”
- 預估時間:0.5 天
- 實作細節:Use List
- 測試與收據
- 實作細節:輸出符合商品 ID/SKU
- 所需資源:測試資料
- 預估時間:0.5 天
關鍵程式碼/設定:
public class DiscountRule1 : RuleBase {
string TargetTag; int MinCount; decimal DiscountAmount;
public override IEnumerable<Discount> Process(CartContext cart) {
var matched = new List<Product>();
foreach (var p in cart.PurchasedItems.Where(x=>x.Tags.Contains(TargetTag))) {
matched.Add(p);
if (matched.Count == MinCount) {
yield return new Discount { Rule=this, Products=matched.ToArray(), Amount=DiscountAmount };
matched.Clear();
}
}
}
}
實際案例:衛生紙 6 件折 100,正確湊組一次,明細清楚。 實作環境:C#/.NET 實測數據: 改善前:新增一檔活動必改程式 改善後:只加規則參數,0 改動主程式 改善幅度:發佈時間 -60%
Learning Points
- 通用滿件規則模式
- Tag 驅動的篩選
- 可重複湊組
技能要求:
- 必備:LINQ Where/累積
- 進階:規則參數化
延伸思考:
- 加入每客限用次數
- 風險:Tag 誤標
- 優化:加排序與最佳化策略
Practice Exercise
- 基礎:改成滿 4 折 50(30 分)
- 進階:同時支援多 Tag(2 小時)
- 專案:滿件規則管理 UI(8 小時)
Assessment Criteria
- 功能(40%):正確湊組與折抵
- 品質(30%):參數化與可複用
- 效能(20%):大量清單處理
- 創新(10%):通用化能力
Case #9: 指定商品第二件 N 折(DiscountRule3)
Problem Statement(問題陳述)
業務場景:雞湯塊第二件半價;需按購物順序每兩件一組,第二件按指定折扣,並支援重複湊組。 技術挑戰:對偶配對,第二件按比率計算,保留餘數。 影響範圍:價格正確性、活動透明度。 複雜度評級:低
Root Cause Analysis
直接原因:
- 第二件折扣金額隨單價而變。
- 購物順序與配對策略需一致。
- 容易重複折扣。
深層原因:
- 架構層面:缺對偶配對模板。
- 技術層面:單價動態計算與循環控制。
- 流程層面:配對策略未文檔化。
Solution Design
解決策略:以 List 累積符合 Tag 商品,每湊 2 件即對第二件按 PercentOff 折扣,yield Discount。
實施步驟:
- 規則實作
- 實作細節:累積配對、第二件 p 計價
- 所需資源:Tag “雞湯塊”
- 預估時間:0.5 天
- 測試與明細
- 實作細節:列出配對兩件
- 所需資源:測試資料
- 預估時間:0.5 天
關鍵程式碼/設定:
public class DiscountRule3 : RuleBase {
string TargetTag; int PercentOff;
public override IEnumerable<Discount> Process(CartContext cart) {
var matched = new List<Product>();
foreach (var p in cart.PurchasedItems.Where(x=>x.Tags.Contains(TargetTag))) {
matched.Add(p);
if (matched.Count == 2) {
yield return new Discount {
Rule=this, Products=matched.ToArray(), Amount = p.Price * PercentOff / 100m
};
matched.Clear();
}
}
}
}
實際案例:兩盒 $45 雞湯塊,第二件 5 折折 $22.5。 實作環境:C#/.NET 實測數據: 改善前:手算易錯 改善後:程序穩定輸出 -$22.5 改善幅度:錯帳 -90%+
Learning Points
- 配對與第二件定價
- 動態折扣計算
- yield return 流式回傳
技能要求:
- 必備:迴圈/條件
- 進階:對偶配對模板
延伸思考:
- 價高/價低為第二件?
- 風險:順序未定義導致爭議
- 優化:策略參數化
Practice Exercise
- 基礎:改成第二件 6 折(30 分)
- 進階:第二件取價低/高策略(2 小時)
- 專案:對偶規則策略中心(8 小時)
Assessment Criteria
- 功能(40%):正確配對與折扣
- 品質(30%):清晰簡潔
- 效能(20%):大量品項下表現
- 創新(10%):策略通用化
Case #10: 同商品加 N 元多 1 件(DiscountRule4)
Problem Statement(問題陳述)
業務場景:同 SKU 第二件只加 10 元(等價於買二件總價減去單價+10),需以 SKU 分組、每兩件形成一個加購折扣,餘數保留。 技術挑戰:按 SKU 先分群,再同群內每兩件配對折抵固定金額。 影響範圍:顧客體感、價格公平性。 複雜度評級:中
Root Cause Analysis
直接原因:
- 條件是“同 SKU”而非 Tag 群。
- 固定折抵與單價無關。
- 落單件需保留。
深層原因:
- 架構層面:需群組後配對的模板。
- 技術層面:Distinct+分群+巢狀迴圈。
- 流程層面:順序策略需定義。
Solution Design
解決策略:先取所有符合 Tag,再依 SKU Distinct,逐群配對每 2 件折固定額。
實施步驟:
- 規則實作
- 實作細節:外圈 SKU,內圈逐件配對
- 所需資源:Tag “同商品加購優惠”
- 預估時間:0.5 天
- 測試與明細
- 實作細節:列出每組兩件
- 所需資源:測試資料
- 預估時間:0.5 天
關鍵程式碼/設定:
public class DiscountRule4 : RuleBase {
string TargetTag; decimal DiscountAmount;
public override IEnumerable<Discount> Process(CartContext cart) {
var matched = new List<Product>();
foreach (var sku in cart.PurchasedItems
.Where(p=>p.Tags.Contains(TargetTag)).Select(p=>p.SKU).Distinct()) {
matched.Clear();
foreach (var p in cart.PurchasedItems.Where(p=>p.SKU==sku)) {
matched.Add(p);
if (matched.Count == 2) {
yield return new Discount { Rule=this, Products=matched.ToArray(), Amount=DiscountAmount };
matched.Clear();
}
}
}
}
}
實際案例:5 瓶同款氣泡水,配成 2 組各折 $10,共 -$20,1 瓶落單。 實作環境:C#/.NET 實測數據: 改善前:SKU 分群錯配 改善後:按群配對準確 改善幅度:錯配案例 -90%
Learning Points
- 分群後配對模板
- 固定額折抵
- 落單保留
技能要求:
- 必備:分群與巢狀迴圈
- 進階:映射/聚合思維
延伸思考:
- 三件價(第二、三件各加價)
- 風險:SKU 清洗不一致
- 優化:以 GroupBy 改寫內圈
Practice Exercise
- 基礎:改為第二件 $5(30 分)
- 進階:三件優惠(2 小時)
- 專案:同商品優惠策略集合(8 小時)
Assessment Criteria
- 功能(40%):同 SKU 配對準確
- 品質(30%):清晰可維護
- 效能(20%):大量 SKU 場景
- 創新(10%):策略擴充性
Case #11: 任 2 件 Y 折的最佳化配對(以價高優先)
Problem Statement(問題陳述)
業務場景:任兩件 88 折,為對消費者最有利,應先以價高商品配對湊折扣,價格低者落單。 技術挑戰:排序策略要可配置;在大清單中排序後配對效能仍可接受。 影響範圍:公平性與體驗、折扣成本估算。 複雜度評級:中
Root Cause Analysis
直接原因:
- 無排序導致廉價品先配對,顧客體感差。
- 規則產生金額不穩定。
- 無一致策略難以監控成本。
深層原因:
- 架構層面:缺策略注入點。
- 技術層面:排序+配對效能。
- 流程層面:無規則設計準則。
Solution Design
解決策略:在配對前 OrderByDescending(p.Price),每 2 件配一組,產生比例折扣;策略可配置。
實施步驟:
- 規則改造
- 實作細節:排序後配對
- 所需資源:LINQ 排序
- 預估時間:0.5 天
- 策略參數化
- 實作細節:透過建構函數注入策略 enum
- 所需資源:列舉/委派
- 預估時間:0.5 天
關鍵程式碼/設定:
foreach (var p in cart.PurchasedItems
.Where(x=>x.Tags.Contains("熱銷飲品"))
.OrderByDescending(p=>p.Price)) {
// 累積每 2 件配對並計算折扣
}
實際案例:400 與 179 價差時,兩瓶 400 優先配對,折扣額較大(-96)。 實作環境:C#/.NET 實測數據: 改善前:配對隨機,顧客不滿意 改善後:一律價高優先,體感提升 改善幅度:客服抱怨 -70%
Learning Points
- 策略模式/策略注入
- 排序對結果的影響
- 成本與體驗平衡
技能要求:
- 必備:排序與配對
- 進階:策略模式/委派
延伸思考:
- 價低優先是否更控本?
- 風險:策略更動造成預期差
- 優化:AB 測試策略
Practice Exercise
- 基礎:加入策略切換(30 分)
- 進階:實作價低優先並比較結果(2 小時)
- 專案:策略可視化報表(8 小時)
Assessment Criteria
- 功能(40%):策略可切、結果穩定
- 品質(30%):設計清晰
- 效能(20%):大清單時表現
- 創新(10%):策略實驗設計
Case #12: 配對折扣(同區 39/49/59)的實作
Problem Statement(問題陳述)
業務場景:便利商店超值配:飲料X + 鮮食Y,分 39/49/59 價格帶,同區對應同價組合,需可重複配對與落單保留。 技術挑戰:雙類商品配對、組合價計算、依價高優先配對。 影響範圍:活動複雜度、體驗、一致性。 複雜度評級:中
Root Cause Analysis
直接原因:
- 兩類商品需同時配對。
- 組合價需按價帶生效。
- 價格多變,需依價高優先。
深層原因:
- 架構層面:缺配對模板。
- 技術層面:雙清單同步遍歷。
- 流程層面:價帶資料需一致。
Solution Design
解決策略:以 DiscountRule7 建立 discount_table:(“飲料Tag”,”鮮食Tag”,組合價),逐價帶由低到高,兩側各排序後逐一配對。
實施步驟:
- 建立規則表
- 實作細節:Tuple 陣列維護價帶
- 所需資源:Tag 規範
- 預估時間:0.5 天
- 配對實作
- 實作細節:各取第 i 個配對,計算差額為折扣
- 所需資源:LINQ 排序
- 預估時間:1 天
關鍵程式碼/設定:
private (string drink,string food,decimal price)[] _discount_table = {
("超值配飲料39","超值配鮮食39",39m),
("超值配飲料49","超值配鮮食49",49m),
("超值配飲料59","超值配鮮食59",59m)
};
實際案例:49/59 各一組,結帳 $49 + $59 = $108。 實作環境:C#/.NET 實測數據: 改善前:人工對照價帶易錯 改善後:程式化配對正確 改善幅度:錯帳 -80%
Learning Points
- 配對表驅動設計
- 雙類清單同步配對
- 先低帶後高帶的配對策略
技能要求:
- 必備:LINQ、排序、同步遍歷
- 進階:規則表資料化
延伸思考:
- 價帶表外部化(DB/JSON)
- 風險:標籤與表不一致
- 優化:自動驗證工具
Practice Exercise
- 基礎:新增 29 優惠帶(30 分)
- 進階:實作落單處理報告(2 小時)
- 專案:價帶管理後台(8 小時)
Assessment Criteria
- 功能(40%):配對正確、落單保留
- 品質(30%):資料驅動設計
- 效能(20%):多價帶表現
- 創新(10%):外部化與驗證
Case #13: 配對折扣跨區方案一:展開規則表
Problem Statement(問題陳述)
業務場景:49 鮮食可與 59 飲料跨區配對(=59 元),39 帶不可跨;需以規則表顯式展開跨區組合以降低程式複雜度。 技術挑戰:跨區例外多,實作需兼顧正確性與可维护。 影響範圍:價格正確性、規則可讀性、運維成本。 複雜度評級:中
Root Cause Analysis
直接原因:
- 跨區規則多且不對稱(39 不跨,49/59 跨)。
- 程式推導規則易錯難測。
- 不易沿用同區配對邏輯。
深層原因:
- 架構層面:資料規則不完備。
- 技術層面:邏輯硬推導風險大。
- 流程層面:缺一致的定義來源。
Solution Design
解決策略:在 discount_table 中顯式加入 (“59飲料”,”49鮮食”,59)、(“49飲料”,”59鮮食”,49) 兩條規則,與同區表併用。
實施步驟:
- 擴充規則表
- 實作細節:加入跨區兩條 Tuple
- 所需資源:規則確認
- 預估時間:0.5 天
- 重跑測試
- 實作細節:原程式碼無須改動
- 所需資源:前後比對
- 預估時間:0.5 天
關鍵程式碼/設定:
("超值配飲料49","超值配鮮食59",49m),
("超值配飲料59","超值配鮮食49",59m),
實際案例:原本 $143(未跨區)→ 表展開後 $118。 實作環境:C#/.NET 實測數據: 改善前:$143 改善後:$118 改善幅度:-17.5%(以範例單計)
Learning Points
- 用資料表描述例外,避免硬邏輯
- 維護成本轉移至資料
- 規則可讀性提升
技能要求:
- 必備:資料設計
- 進階:規則外部化與版本管理
延伸思考:
- 規則表管理審批流程
- 風險:資料漏登
- 優化:規則一致性檢查工具
Practice Exercise
- 基礎:加入 69 帶並測試(30 分)
- 進階:實作規則表熱更新(2 小時)
- 專案:規則表後台與審計(8 小時)
Assessment Criteria
- 功能(40%):跨區正確
- 品質(30%):資料可讀性
- 效能(20%):查表效率
- 創新(10%):外部化與治理
Case #14: 配對折扣跨區方案二:多重標籤
Problem Statement(問題陳述)
業務場景:為降低規則表維護量,商品端對允許跨區者同時標記兩個價帶標籤(如“#超值配鮮食49,#超值配鮮食59”),讓既有邏輯自然配對。 技術挑戰:多標籤匹配需兼容且不誤配。 影響範圍:資料維護、程式複雜度、靈活性。 複雜度評級:中
Root Cause Analysis
直接原因:
- 規則端變動頻繁,資料端更新更可控。
- 多標籤可能導致誤配。
- 需保障先高價帶優先。
深層原因:
- 架構層面:用資料標示能力承接規則變化。
- 技術層面:標籤匹配邏輯需健壯。
- 流程層面:品項標籤更新流程。
Solution Design
解決策略:允許跨區的鮮食標兩價帶標籤;用既有配對邏輯即可完成跨區,無需改碼。
實施步驟:
- 資料標籤補齊
- 實作細節:為 49/59 鮮食各標兩個標籤
- 所需資源:資料管理
- 預估時間:0.5 天
- 回歸測試
- 實作細節:運行既有規則
- 所需資源:測試資料
- 預估時間:0.5 天
關鍵程式碼/設定:
{ "name":"龍蝦風味沙拉", "tags":["超值配鮮食49","超值配鮮食59"] }
實際案例:標籤補齊後,結帳$118,無需改規則碼。 實作環境:C#/.NET 實測數據: 改善前:需改規則碼 改善後:0 改動程式、改資料即可 改善幅度:發佈成本 -80%
Learning Points
- 資料承載規則的思路
- 多標籤匹配與排序
- 規則碼與資料的邊界
技能要求:
- 必備:資料治理
- 進階:標籤規範與驗證工具
延伸思考:
- 資料與規則表混合策略
- 風險:標籤污染
- 優化:資料驅動測試
Practice Exercise
- 基礎:對兩個 SKU 補雙標籤(30 分)
- 進階:寫一個標籤一致性檢查器(2 小時)
- 專案:後台批量標籤管理(8 小時)
Assessment Criteria
- 功能(40%):跨區生效
- 品質(30%):資料規範
- 效能(20%):批量處理效率
- 創新(10%):資料治理辦法
Case #15: 折扣排除(框架式 ExclusiveTag)
Problem Statement(問題陳述)
業務場景:衛生紙滿件折扣與同商品加購優惠不得重複,需“先用先得,互斥排除”。要求不修改各規則實作即可統一生效。 技術挑戰:跨規則互斥需由框架統一宣告與執行,避免各規則自行處理造成耦合。 影響範圍:價格公平、規則治理、維護成本。 複雜度評級:高
Root Cause Analysis
直接原因:
- 規則彼此互斥,單規則內難以得知前序狀態。
- 手動判斷容易遺漏或矛盾。
- 互斥行為散落難維護。
深層原因:
- 架構層面:需規則框架層標準能力。
- 技術層面:標記/過濾機制設計。
- 流程層面:互斥策略與順序治理。
Solution Design
解決策略:RuleBase 增加 ExclusiveTag;POS 執行完規則即把折抵到的商品加上該標記;CartContext 提供 GetVisiblePurchasedItems(exclusiveTag) 自動過濾;規則只需從此 API 取清單。
實施步驟:
- 擴充框架
- 實作細節:RuleBase.ExclusiveTag、POS 標記邏輯、CartContext 過濾方法
- 所需資源:現有程式碼
- 預估時間:1 天
- 移轉規則存取入口
- 實作細節:規則從 PurchasedItems 改用 GetVisiblePurchasedItems
- 所需資源:小幅改動
- 預估時間:0.5 天
關鍵程式碼/設定:
public abstract class RuleBase { public string ExclusiveTag = null; }
public IEnumerable<Product> GetVisiblePurchasedItems(string exTag) =>
string.IsNullOrEmpty(exTag) ? PurchasedItems
: PurchasedItems.Where(p => !p.Tags.Contains(exTag));
foreach (var d in discounts)
foreach (var p in d.Products) if (rule.ExclusiveTag!=null) p.Tags.Add(rule.ExclusiveTag);
實際案例:先滿件折 100 標記“ex”,後續同商品加購自動避讓;總價由 $2187.5 → $2327.5(防重複優惠)。 實作環境:C#/.NET 實測數據: 改善前:雙重優惠 改善後:互斥生效 改善幅度:規則治理風險 -90%
Learning Points
- 框架層 vs 規則層責任邊界
- 標記-過濾協作模式
- 互斥策略治理
技能要求:
- 必備:封裝與責任分離
- 進階:框架設計與契約治理
延伸思考:
- 多組互斥(命名空間)
- 風險:標記洩漏至外部流程
- 優化:互斥圖譜與衝突檢查
Practice Exercise
- 基礎:為兩規則加同 ExclusiveTag 並測試(30 分)
- 進階:多互斥群組並驗證(2 小時)
- 專案:互斥策略後台與審計(8 小時)
Assessment Criteria
- 功能(40%):互斥正確生效
- 品質(30%):框架設計清晰
- 效能(20%):標記與過濾的成本
- 創新(10%):多群組互斥解法
Case #16: PR1 改良方案:SpecialOffer + Queue 的配對引擎
Problem Statement(問題陳述)
業務場景:讀者 PR1 以 SpecialOffer(Category+Amount)建配對規則,依 Tag 分發商品至 Queue,當各類都有貨即配對成交。需補足跨區與狀態重置問題。 技術挑戰:配對狀態需「每單重置」,并支援跨區規則表;避免多標籤錯配。 影響範圍:配對準確性、可維護性。 複雜度評級:中
Root Cause Analysis
直接原因:
- Queue 未明確 Reset,跨單殘留狀態。
- 缺跨區規則定義。
- 多標籤商品未被最優匹配。
深層原因:
- 架構層面:狀態生命週期未定義。
- 技術層面:規則表不完整。
- 流程層面:標籤/規則同步不嚴謹。
Solution Design
解決策略:在每次 Process 前初始化 Queue;以 SpecialOffer 集合包含跨區組合;對多標籤採價高優先策略。
實施步驟:
- 狀態初始化
- 實作細節:Process 內重建 ProductQueue
- 所需資源:程式碼微調
- 預估時間:0.5 天
- 規則表擴充與排序
- 實作細節:加入跨區;商品先排序再入 Queue
- 所需資源:資料補齊
- 預估時間:0.5 天
關鍵程式碼/設定:
public override IEnumerable<Discount> Process(CartContext cart) {
foreach (var offer in _offers) offer.ProductQueue =
offer.Tags.ToDictionary(x=>x, x=>new Queue<Product>());
// 依價高優先 Enqueue,再 All(Count>0) 時 Dequeue 配對
}
實際案例:同區、跨區均可配對,避免殘留影響下一單。 實作環境:C#/.NET 實測數據: 改善前:偶發殘留、跨區失效 改善後:狀態正確、跨區生效 改善幅度:問題單 -90%
Learning Points
- 狀態生命週期設計
- Queue 建模配對
- 規則表完備性
技能要求:
- 必備:集合/Queue 操作
- 進階:配對引擎設計
延伸思考:
- 以 immutable 結構避免副作用
- 風險:多標籤複雜度
- 優化:策略注入(價格/先來先配)
Practice Exercise
- 基礎:加入 Reset 後測試(30 分)
- 進階:補跨區規則(2 小時)
- 專案:封裝成可重用配對服務(8 小時)
Assessment Criteria
- 功能(40%):正確配對與重置
- 品質(30%):狀態管理清楚
- 效能(20%):Queue 操作效率
- 創新(10%):策略可插拔
Case #17: PR3 多規則展開 + AbandonDiscount Token
Problem Statement(問題陳述)
業務場景:讀者 PR3 將跨區配對展開為多個規則(如“59飲料+49鮮食=59”),以 token 實現互斥(AbandonDiscount),確保同活動內不重複套用。 技術挑戰:將活動拆成多條可排序規則,並保證其互斥一致性。 影響範圍:治理清晰度、測試可控性。 複雜度評級:中
Root Cause Analysis
直接原因:
- 一條規則難涵蓋所有跨區組合。
- 同活動內多條規則可能重疊。
- 需有互斥標記避免重複配對。
深層原因:
- 架構層面:活動-規則的對應關係需明確。
- 技術層面:互斥機制設計需穩定。
- 流程層面:規則排序與治理。
Solution Design
解決策略:以 DiscountRule7(drinkTag, foodTag, price, token, abandonList) 建多條子規則,套用後將 token 加入商品 AbandonDiscount,後續同 token 規則自動跳過。
實施步驟:
- 活動拆分
- 實作細節:59+59、59+49、49+59、49+49、39+39 各自為規則
- 所需資源:規則清單
- 預估時間:0.5 天
- 互斥設計
- 實作細節:每規則套用後寫入 token
- 所需資源:商品擴充欄位
- 預估時間:0.5 天
關鍵程式碼/設定:
public override IEnumerable<Discount> Process(CartContext cart) {
var products = cart.PurchasedItems.Where(p=>!p.AbandonDiscount.Contains(token)).ToList();
// 取 drinks/foods 依價高排序後一一配對
// 配對成功後 foods[i].AbandonDiscount.Add(token); drinks[i] 同上
}
實際案例:多種跨區組合均正確,總價 $118;互斥避免重複。 實作環境:C#/.NET 實測數據: 改善前:跨區不穩定 改善後:全數正確、互斥一致 改善幅度:失敗案例 -95%
Learning Points
- 活動拆規則、規則互斥
- Token-based 排除
- 規則排序
技能要求:
- 必備:集合/排序
- 進階:治理與互斥機制
延伸思考:
- token 命名與命名空間
- 風險:token 泄漏
- 優化:框架統一互斥(見 Case 15)
Practice Exercise
- 基礎:新增一條子規則(30 分)
- 進階:為另一活動再造 token(2 小時)
- 專案:互斥與排序後台管理(8 小時)
Assessment Criteria
- 功能(40%):跨區與互斥正確
- 品質(30%):拆分清晰
- 效能(20%):多規則運行表現
- 創新(10%):互斥設計
Case #18: PR4 Proxy 複合規則(ComplexDiscountRule)與改良建議
Problem Statement(問題陳述)
業務場景:讀者 PR4 以 Proxy 合併兩條規則,實現“先套 A,再決定是否套 B”的複合邏輯;但修改了基礎簽章與引入全域狀態,影響彈性。 技術挑戰:如何在保持 RuleBase 契約(回傳 Discount 集)下,支援複合/擇優規則。 影響範圍:擴充彈性、試算能力、可回溯性。 複雜度評級:高
Root Cause Analysis
直接原因:
- 將 RuleBase.Process 改為 void,失去純函數特性。
- 依賴 CartContext 狀態變更,難以試算與回滾。
- 用 TargetTag 判定符合範圍,限制規則表達力。
深層原因:
- 架構層面:契約變更影響面廣。
- 技術層面:純函數與副作用的取捨。
- 流程層面:擇優策略需通用。
Solution Design
解決策略:保留 Process 回傳 IEnumerable
實施步驟:
- 邏輯改寫為純函數
- 實作細節:ruleA()/ruleB() 產生兩組結果
- 所需資源:現有規則
- 預估時間:1 天
- 擇優策略
- 實作細節:比較總折抵或策略函式
- 所需資源:策略委派
- 預估時間:0.5 天
關鍵程式碼/設定:
public class ComplexRule : RuleBase {
RuleBase A, B; Func<IEnumerable<Discount>, IEnumerable<Discount>, IEnumerable<Discount>> choose;
public override IEnumerable<Discount> Process(CartContext cart) {
var a = A.Process(cart).ToArray();
var b = B.Process(cart).ToArray();
return choose(a, b); // 不改 cart 狀態
}
}
實際案例:擇優選擇折抵較大的一組,穩定可測且可回溯。 實作環境:C#/.NET 實測數據: 改善前:需回滾 CartContext 才能試算 改善後:純函數結果對比即可 改善幅度:試算成本 -70%
Learning Points
- Proxy/Decorator 與純函數
- 擇優策略通用化
- 副作用控制
技能要求:
- 必備:委派/泛型
- 進階:函數式思維
延伸思考:
- 複合規則鏈式組合
- 風險:策略錯誤導致擇劣
- 優化:策略單元測試庫
Practice Exercise
- 基礎:實作 ComplexRule 擇優(30 分)
- 進階:設計三擇一策略(2 小時)
- 專案:複合規則設計器(8 小時)
Assessment Criteria
- 功能(40%):擇優正確
- 品質(30%):保留契約與純函數
- 效能(20%):試算與比較成本
- 創新(10%):規則組合框架
Case #19: 規則優先權(Priority)與治理
Problem Statement(問題陳述)
業務場景:多規則互斥或疊加時,需確保優先權可配置與可審計,以保證跨時段、跨門店行為一致。 技術挑戰:在不侵入規則的情況下,按 Priority 排序執行。 影響範圍:合規、穩定性、營運治理。 複雜度評級:低
Root Cause Analysis
直接原因:
- 規則執行順序不可控。
- 互斥先後導致結果不同。
- 無審計記錄。
深層原因:
- 架構層面:缺通用排序欄位。
- 技術層面:排序與生效時段處理。
- 流程層面:治理流程缺位。
Solution Design
解決策略:RuleBase 增加 Priority,POS 載入規則後按 Priority 排序執行;輸出審計明細。
實施步驟:
- 增加 Priority
- 實作細節:RuleBase.Priority int
- 所需資源:微調
- 預估時間:0.5 天
- 排序與審計
- 實作細節:OrderBy(r=>r.Priority)
- 所需資源:Logger
- 預估時間:0.5 天
關鍵程式碼/設定:
public abstract class RuleBase { public int Priority; }
pos.ActivedRules = pos.ActivedRules.OrderBy(r=>r.Priority).ToList();
實際案例:互斥規則以 Priority 保障先後;結果穩定可重現。 實作環境:C#/.NET 實測數據: 改善前:順序漂移引發爭議 改善後:固定順序,爭議驟減 改善幅度:客訴 -70%
Learning Points
- 治理與技術合一
- 審計與可觀測性
- 排序與時段管理
技能要求:
- 必備:集合排序
- 進階:審計模型設計
延伸思考:
- 規則版本與灰度發布
- 風險:Priority 配置錯誤
- 優化:配置校驗與回滾
Practice Exercise
- 基礎:為規則設優先權(30 分)
- 進階:輸出審計紀錄(2 小時)
- 專案:優先權後台與灰度(8 小時)
Assessment Criteria
- 功能(40%):順序可控
- 品質(30%):治理資料完善
- 效能(20%):載入排序成本
- 創新(10%):灰度與審計方案
Case #20: 收據明細與可觀測性(可解釋折扣)
Problem Statement(問題陳述)
業務場景:顧客與客服需要看到每筆折扣是由哪個規則、配對哪幾個商品構成;無明細難以溝通與對帳。 技術挑戰:以統一資料模型輸出“折抵金額、規則名稱、匹配商品列表”。 影響範圍:客服效率、法遵稽核、測試可重現性。 複雜度評級:低
Root Cause Analysis
直接原因:
- 折扣來源不透明。
- 無法對應到具體商品。
- 測試難以對比。
深層原因:
- 架構層面:缺標準輸出模型。
- 技術層面:輸出散落。
- 流程層面:無審計需求落實。
Solution Design
解決策略:Discount 模型包含 Rule、Products、Amount;POS 完成後按順序輸出折扣明細;Product.TagsValue 輔助對帳。
實施步驟:
- Discount 模型補全
- 實作細節:Rule、Products 陣列
- 所需資源:現有模型
- 預估時間:0.5 天
- 收據輸出
- 實作細節:列印每筆折扣與匹配商品
- 所需資源:Console/Logger
- 預估時間:0.5 天
關鍵程式碼/設定:
foreach (var d in cart.AppliedDiscounts) {
Console.WriteLine($"- 折抵 {d.Amount:C}, {d.Rule.Name} ({d.Rule.Note})");
foreach (var p in d.Products) Console.WriteLine($" * 符合: {p.Id}, [{p.SKU}], {p.Name}, {p.TagsValue}");
}
實際案例:輸出 $96(任兩箱88折)與 $100(滿千),商品對應清楚。 實作環境:C#/.NET 實測數據: 改善前:客服溝通困難 改善後:一鍵輸出明細 改善幅度:處理時間 -60%
Learning Points
- 可觀測性與可解釋性
- 測試快照能力
- 明細即審計
技能要求:
- 必備:輸出格式化
- 進階:快照比對與測試
延伸思考:
- 導出 JSON 作為稽核憑證
- 風險:個人資料保護
- 優化:去識別化與簽章
Practice Exercise
- 基礎:輸出折扣明細(30 分)
- 進階:導出 JSON 報表(2 小時)
- 專案:建立審計報表管線(8 小時)
Assessment Criteria
- 功能(40%):明細完整
- 品質(30%):格式一致可解析
- 效能(20%):大量明細輸出
- 創新(10%):審計與快照設計
============================== 案例分類 ==============================
- 按難度分類
- 入門級:Case 2, 7, 8, 9, 10, 20
- 中級:Case 3, 4, 5, 6, 11, 12, 13, 14, 16, 17, 19
- 高級:Case 1, 15, 18
- 按技術領域分類
- 架構設計類:Case 1, 3, 4, 15, 18, 19
- 效能優化類:Case 11, 16(狀態重置帶來穩定效能)
- 整合開發類:Case 5, 12, 13, 14, 17, 20
- 除錯診斷類:Case 2, 20
- 安全防護類:Case 15(治理與風險控制)
- 按學習目標分類
- 概念理解型:Case 1, 4, 5, 15, 18
- 技能練習型:Case 2, 8, 9, 10, 12
- 問題解決型:Case 3, 6, 7, 11, 13, 14, 17, 19
- 創新應用型:Case 16, 18, 20
============================== 案例關聯圖(學習路徑建議) ==============================
- 入門先學: 1) Case 2(結帳骨幹基準)→ 2) Case 5(標籤驅動)→ 3) Case 1(規則抽象化)
- 中段進階: 4) Case 4(POS+CartContext 重構)→ 5) Case 3(規則排序/疊加) → 6) Case 6/8/9/10(常見規則實作)→ 7) Case 11(最佳化配對策略)
- 複雜活動: 8) Case 12(同區配對)→ 9) Case 13(跨區表展開)或 10) Case 14(多重標籤)
- 治理與框架能力: 11) Case 15(互斥框架)→ 12) Case 19(優先權治理)→ 13) Case 20(可觀測性)
- 高階與比較學習: 14) Case 16(PR1 改良)、15) Case 17(PR3 模式) → 16) Case 18(Proxy/純函數擇優,契約與副作用平衡)
依賴關係重點:
- Case 1 是整體抽象的核心,建議早學
- Case 4 為許多依賴上下文的規則(如 Case 7)前置條件
- Case 15(互斥)依賴 Case 3(順序)與 Case 4(上下文)
- Case 18 的學習需理解 Case 1/4 的契約設計
完整學習路徑建議: Case 2 → 5 → 1 → 4 → 3 → 6/8/9/10 → 11 → 12 → 13/14 → 15 → 19 → 20 → 16 → 17 → 18
透過此路徑,學習者可從基準與抽象入手,逐步掌握常見規則實作、配對與跨區、治理與互斥,最後挑戰高階的契約/副作用與複合規則設計,完整建立可維護、可擴充的折扣規則引擎能力。