1. 程式人生 > 程式設計 >領域驅動設計DDD之工廠

領域驅動設計DDD之工廠

為什麼需要工廠

  1. 當建立一個複雜物件或聚合的過程很複雜並且暴露出了過多的內部結構時,我們則可以使用工廠進行封裝。一個物件在它的生命週期中要承擔大量的職責,如果再讓複雜物件負責自身的建立,那麼職責過載將會導致問題。

  2. 我們設計好領域模型供客戶方呼叫,但如果客戶方也必須使用如何裝配這個物件,則必須知道物件的內部結構。好比你去駕校學車,卻得先學會發動機的原理。對客戶方開發來說這是很不友好的。其次,複雜物件或者聚合當中的領域知識(業務規則)需要得到滿足,如果讓客戶方自己裝配複雜物件或聚合的話,就會將領域知識洩露到客戶方程式碼中去。

  3. 物件的建立本身可以是一個主要操作,但被建立的物件並不適合承擔複雜的裝配操作。將這些職責混在一起可能產生難以理解的拙劣設計。讓客戶直接負責建立物件又會使客戶的設計陷入混亂,並且破壞被裝配物件或聚合的封裝,而且導致客戶與被建立物件的實現之間產生過於緊密的耦合。

最重要的一點就是隱藏建立物件的細節

定義

複雜物件的建立是領域層的職責,但這項任務並不一定屬於那些用於表示模型的物件,他們沒有對應模型中的事物,但又確實承擔了領域層的職責。 應該將建立複雜物件和聚合的職責轉移給單獨的物件,這個物件本身可能沒有承擔領域模型中的職責,但它仍然領域設計的一部分。提供一個封裝所有複雜裝配操作的介面,而且這個介面不需要客戶引用要被例項化的物件的具體類。在建立聚合時要把它作為一個整體,並確保它滿足固定規則。

工廠的設計要點

1.每個建立方法都應該是原子的,並保證生成的物件處於一致的狀態。

2.可以使用獨立的工廠或者在聚合根上使用工廠方法。當A物件的建立主要使用了B物件的資料或者規則時,那麼可以在B物件上建立一個工廠方法來生成A物件。

3.以下情況只需使用建構函式即可。

  • 類僅僅是一種型別,沒有其他子類,沒有實現多型性。
  • 客戶關心的是實現類。
  • 客戶可以訪問物件的所有屬性,因此向客戶公開的建構函式中沒有巢狀的物件建立。
  • 構造過程很簡單。
  • 公共建構函式必須遵守與工廠相同的規則,必須是原子操作且滿足所有固定規則。
  • 不要在建構函式中呼叫其他建構函式,應保持建構函式的簡單。

4.工廠方法的引數應該是較低層的物件。比如裝配一輛汽車,應該傳入較低層抽象的輪胎,發動機等物件。

當我們利用購物車模型進行結算的時候,可以從購物車模型的下單方法去生成一個訂單模型。這就通過購物車聚合的工廠方法去生成了訂單聚合。

舉個例子

我們以一個論壇物件發起一個討論為例

public class Forum {
    
    public Discussion startDiscussion(DiscussionId aDiscussionId,Author anAuthor,String aSubject) {
    
        if(this.isClosed()){
            throw new IllegalStateException("Forum is closed!");
        }
        
        
        Discussion discussion = new Discussion(this.tenant(),this.forumId(),aDiscusstionId,anAuthor,aSubject);
                                               
        // .. 釋出領域事件
        
    
        return discusstion;    
        
    }
    
    
}
複製程式碼

客戶端如何使用這個模型呢?

// 由論壇實體生成這個討論
Discussion discussion = aForum.startDiscussion(this.discussionRepository.nextIdentity(),new Author("jdoe","John Doe","[email protected]"),"Dealing with Aggregate Concurrency Issues");
// 儲存這個討論
this.discussionRepository.add(discussion);

複製程式碼

工廠不僅達到了封裝建立物件的細節,並有效的表達了限界上下文中的通用語言,減輕客戶端在建立新聚合例項時的負擔,確保所建立的例項處於正確的狀態(符合業務規則)。

工廠有多種形式,可以是一個獨立的Factory物件,也可以是聚合根上的工廠方法,也可以是領域服務。 工廠不僅用於物件生命初期的建立,還用於在物件生命週期的中期從資料庫中的資料裝配成聚合的情況。

關於DDD的理解各有不同,歡迎網友評論一起探討。

轉自我的個人部落格 vc2x.com