天天看點

領域模組化實作思考

領域模組化實作思考

“Javaeye論壇-領域模組化”闆塊有很多讨論,不再引述,直接列舉我的觀點。

JavaEE中領域模組化的困境包括:

1) 類膨脹。 需要職責理順,分散和委托出去。

2) 無法擺脫Entity的Domain Service注入?

思路:

1. 目前的 Service 模式是一種元件化的,形式上是 OO 的,實質上是元件的,它能很好的解決現有問題。 但忽視了領域對象之前的天然關聯性。

2. 領域模型特征: 普遍共識一般是Domain Object要求“ 資料 + 行為 ”的完整封裝,對象執行個體的行為基于自己的資料,對象之間存在資料關聯(Data Association)和行為關聯(Behavior Association)。此外領域對象還能響應事件。

一個應用的領域對象依據其互相關聯,可由一個根對象(Root Model) 導航擷取到任何一個的Domain Object。

是以一個完整的領域模型可以抽象為:

Domain Model = Data + Association + Behavior + Event

3. 恰當平衡領域模組化思想和實踐的沖突。

第一個問題:如類膨脹,就是談的很多的充血問題。随着系統發展,一個Domain Object要承擔的Behavior增多,代碼中的Method增多,導緻檔案龐大。 這更主要是一個實作階段的問題,但不能不認真考慮。

解決充血肯定要反向思考,即給對象“放血”。将行為分散,實作角度需要增加Behavior類或接口,協同建構Domain Model。

Qi4j 架構基本實作了這一點,Domain Object設計和方法定義完全靠 Interface 和 Interface繼承; 方法實作類為Mixin,隻關注它要實作的Interface,子類為Composite模式,實作了很好的放血和分散。

如:

Domain Object 定義

public interface Speaker
{
    String sayHello();
}
           

方法實作

public class SpeakerMixin
    implements Speaker
{
    public String sayHello()
    {
        return "Hello, World!";
    }
}
           

子類(應該說是接口)定義

@Mixins( SpeakerMixin.class )
public interface PoliticianComposite extends Composite, Speaker  // +others
{
}
           

但Qi4j 還有Concern等很多概念,看它的範例代碼,感覺巨複雜,大量用了Annotation,不很喜歡。

3) 領域模組化對使用者(程式員)要簡單,友好。

現有架構太多的EJB,Service,DAO等架構要求的類,分層清晰,但導緻代碼增多,開發量和使用難度增加。當然,因為這種架構設計的清晰,規範性,在實踐中獲得了很大成功,功勞不可忽視。

新一代的開發架構,如果要面向“領域驅動設計”,需要将 Service,DAO,VO等概念進行融合,實作Data 和Behavior的重新聚合,而且Behavior不管它是原子性的CRUD,還是粗粒度的Business Method。

4) 類設計思路1:Behavior類繼承 Data 類,這樣使用者面對的是資料和Behavior統一的對象執行個體;

5) 類設計思路2:Domain Object恰當劃分Sub Domain, 避免Behavior膨脹。

6) 類設計思路3:1關聯的對象( order.customer ) 既有資料,又有Behavior,不存在什麼問題,Hibernate等已經很好支援; 但N關聯的對象( 如:user.orders ) 是一個集合(Collection)仍是以Data Model為中心;需要變為以“Behavior + Data Model”為中心,重點在Behavior;需要一個集合對Element成員有CRUD操作, 特别是更業務性的操作。

7) 跨環境( Context )問題。

一個Domain Object 在一個系統的不同子系統,不同領域有不同的Data Model和Behavior,是以對Domain Object需要按Context 進行關注。

一個基類如Person如果在不同Context有不同的表現,Manager,Employee,Sale,Clerk等,就需要按各自 Context 設計,而不能單線繼承的設計。

思考的程式設計模型:

Category extends CategoryDO {
	void deleteProduct(String productId); 
 }

Category category = Categorys.find("sss");
  category.getId();

  category.deleteProduct("xxxx");

  category.getProducts().delete("sss");

  category.getProducts().add("ddddd");

  category.getProducts().query("xxxx");
           

[參考資料]

1. Robbin domain model的延伸讨論 http://www.iteye.com/topic/57075

2. Taowen 貧血的Domain Model http://www.iteye.com/topic/191261

3. Taowen 再論領域模型的困境 http://www.iteye.com/topic/401223

4. Lifethinker 一個簡單例子:貧血模型or領域模型 http://www.iteye.com/topic/283668

5. javaboy2006 基于DDD項目的設計總結 http://www.iteye.com/topic/351597

繼續閱讀