本文探討領域模型設計:貧血 vs 充血模型、實體關聯關係、NHibernate 映射檔案與屬性兩種配置方式。
僅含屬性(狀態),無行為。業務邏輯集中在 Service 層。
public class OrderInfo
{
public virtual int OrderId { get; set; }
public virtual DateTime Date { get; set; }
public virtual string UserId { get; set; }
public virtual decimal OrderTotal { get; set; }
public virtual IList<LineItemInfo> LineItems { get; set; }
public virtual int? AuthorizationNumber { get; set; }
}
public class OrderManager
{
public IOrderDao CurrentDao { get; set; }
public object Save(OrderInfo entity)
{
ProcessCreditCard(entity);
return CurrentDao.Save(entity);
}
private void ProcessCreditCard(OrderInfo entity)
{
entity.AuthorizationNumber = new Random().Next();
}
}
優點:層次分明。缺點:Service 易膨脹、難維護。
屬性與行為封裝在實體內。
public class OrderInfo
{
// ... 屬性同前
public void ProcessCreditCard()
{
this.AuthorizationNumber = new Random().Next();
}
}
優點:內聚性高、重用性好。.NET 專案多採貧血模型。
public class OrderInfo
{
public virtual IList<LineItemInfo> LineItems { get; set; }
}
public class LineItemInfo
{
public virtual OrderInfo Order { get; set; }
// ... 其他屬性
}
NHibernate 雙向外鍵會循環參考,序列化需注意。
不需額外組件,脫離 ORM 仍可用。
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="PetShopOrder.Domain" namespace="PetShopOrder.Domain">
<class name="OrderInfo" table="Orders" lazy="true">
<id name="OrderId" column="OrderId" type="Int32">
<generator class="native" />
</id>
<property name="Date" type="DateTime">
<column name="OrderDate" not-null="true" />
</property>
<property name="UserId" type="String">
<column name="UserId" length="20" not-null="true" />
</property>
<bag name="LineItems" inverse="true" lazy="true" generic="true" cascade="all" table="LineItem">
<key column="OrderID" />
<one-to-many class="LineItemInfo" />
</bag>
</class>
</hibernate-mapping>
屬性標註,省配置檔但需引用組件。
服務層回傳 DTO,可透過 Linq 查詢實體投影為匿名型別/DTO,省略業務模型層。