首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

領域驅動設計程式碼實踐:從資料導向轉向行為豐富的領域模型

     編輯:關於.NET

緣起:為什麼關注 DDD

Eric Evans 《領域驅動設計》出版十週年,其核心在於「以領域為中心」建模,而非以資料庫為中心。Jimmy Nilsson 推薦此書「如詩般美妙」,作者在研讀並參加 Evans 工作坊後,嘗試將 DDD 技術模式套用於 Entity Framework 專案,分享心得供同好參考。

核心原則:建模時暫忘持久化

設計實體類別時,易陷入「EF 如何對應資料表」的思維。除非你的業務就是資料儲存(如 Dropbox),持久化只是輔助性關注點。擁有成熟 ORM 技巧(Fluent API、AutoMapper)者,應先專注領域行為與不變條件,事後再處理對應;極端情況下可建立獨立持久化模型對應舊資料庫。

封裝與行為:私有 Setter、公開語意方法

屬性 setter 設為 private(或 protected),透過具體業務方法修改狀態,而非暴露 SetLastName 等貧血操作。

public class Customer : Contact {
    public Customer(string firstName, string lastName, string email) { ... }
    internal Customer() { } // EF 所需無參建構子
    public void CopyBillingAddressToShippingAddress() { ... }
    public void CreateNewShippingAddress(string street, string city, string zip) { ... }
    public void CreateBillingInformation(string street, string city, string zip,
        string creditCardNumber, string bankName) { ... }
    public void SetCustomerContactDetails(string email, string phone, string companyName) { ... }
    public string SalesPersonId { get; private set; }
    public CustomerStatus Status { get; private set; }
    public Address ShippingAddress { get; private set; }
    public Address BillingAddress { get; private set; }
    public CustomerCreditCard CreditCard { get; private set; }
}
public class Contact : Identity {
    public string CompanyName { get; protected set; }
    public string EmailAddress { get; protected set; }
    public string Phone { get; protected set; }
}
public void SetCustomerContactDetails(string email, string phone, string companyName) {
    EmailAddress = email; Phone = phone; CompanyName = companyName;
}

Customer 作為聚合根,負責維護聚合內不變條件(如地址、信用卡的一致性)。公開的是行為,而非屬性。

視情況採用 CRUD:別過度設計

並非所有子系統都需要完整 DDD。簡單的建立/讀取/更新/刪除(CRUD)場景(如聯絡人記錄),使用一般 EF Code First 類別即可。系統通常混合「核心領域(DDD)」與「支撐子系統(CRUD)」,需明確劃分界定上下文邊界。

跨上下文共享資料的取捨

傳統追求「重用」導致跨系統共用實體類別與資料表,耦合度極高。DDD 建議:

  • 必要時才共享,且透過防腐層(服務/訊息佇列)轉換。
  • 輕量資料(如人員姓名)可接受適度複製到多個資料表/資料庫,換取架構簡潔。
  • 各上下文只保留所需欄位(定價上下文只需 ClientId + Status,聯絡人上下文才需姓名)。

下一步預告

下一篇將討論「貧血領域模型」vs「豐富領域模型」、單向關聯設計、EF 持久化對應考量等進階主題。

練習建議:檢視現有類別,嘗試將 setter 隱藏、補上語意業務方法(禁用 SetLastName)。

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