首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

領域驅動設計:電子商務系統中「購買商品」屬於哪個類?——領域服務而非實體

     編輯:程式設計綜合問答

誤區分析

初學者傾向將「購買商品」歸屬於 Product(商品)或 User(用戶)類,導致實體類膨脹、職責不清。

正確建模:領域服務

  • Product / User 為實體/值物件:僅封裝**狀態**(屬性)與**不變約束**(如價格>0、庫存≥0)。
  • 購買流程為「領域服務」:協調多個實體、外部資源(支付、庫存、優惠券),包含**業務流程邏輯**而非單一實體行為。

代碼結構示例

// 實體/值物件 - 僅狀態與自衛約束
public class Product {
    public string Id { get; private set; }
    public string Name { get; private set; }
    public decimal Price { get; private set; }
    public int Stock { get; private set; }
    public void ReduceStock(int qty) { if (qty > Stock) throw new DomainException(\"庫存不足\"); Stock -= qty; }
}

public class User {
    public string Id { get; private set; }
    public string Name { get; private set; }
    public UserLevel Level { get; private set; }
}

// 領域服務 - 協調購買流程
public class PurchaseService {
    private readonly IProductRepository _productRepo;
    private readonly IOrderRepository _orderRepo;
    private readonly IPaymentGateway _payment;
    private readonly ICouponService _coupon;

    public Order Purchase(User buyer, string productId, int quantity, string couponCode) {
        // 1. 獲取聚合根
        Product product = _productRepo.Get(productId);
        // 2. 業務驗證
        if (product.Stock < quantity) throw new DomainException(\"庫存不足\");
        // 3. 計算價格(含優惠)
        decimal total = product.Price * quantity;
        Coupon coupon = _coupon.Validate(couponCode, buyer, total);
        total = coupon.Apply(total);
        // 4. 支付
        PaymentResult pay = _payment.Charge(buyer.Id, total);
        if (!pay.Success) throw new DomainException(\"支付失敗: \" + pay.Message);
        // 5. 扣減庫存、建立訂單
        product.ReduceStock(quantity);
        Order order = new Order(buyer.Id, productId, quantity, total, pay.TransactionId);
        _orderRepo.Save(order);
        // 6. 發送領域事件(可選)
        DomainEvents.Raise(new OrderPlacedEvent(order));
        return order;
    }
}

為什麼不放在 Product 或 User?

放入 Product放入 User放入 PurchaseService
違反單一職責:商品不應知道支付、優惠券、訂單用戶不應知道庫存扣減、訂單持久化✅ 職責單一:協調流程,不持有狀態
循環依賴:Product 需引用 Payment、Order、CouponUser 需引用 Product、Order、Payment✅ 依賴抽象,易測試、易替換
難以單元測試(需 Mock 大量外部服務)同左✅ 可 Mock Repository/Gateway 純單元測試

進階:應用服務 vs 領域服務

  • 應用服務:處理 HTTP 請求、事務邊界、DTO 轉換、安全驗證,調用領域服務。
  • 領域服務:純業務邏輯,無基礎設施依賴(透過介面注入)。

總結

**購買商品屬於領域服務**,而非實體方法。實體專注「是什麼」(狀態+不變約束),服務專注「怎麼做」(跨實體流程協調)。這是 DDD 核心分層思想,也是從貧血模型走向豐富領域模型的關鍵一步。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved