今天終於在一個大型專案中運用了DDD

gameboyLV發表於2013-01-16

先說說之前幾次DDD專案失敗的案例,其實也不能算是失敗,只是沒有領會DDD的思想。

之前的DDD是建立在資料層之上的,首先是每張資料表對應一個資料實體,每個資料實體由泛型的DAO管理,DAO又被資料上下文繼承以實現事務,這就構成了資料層,業務程式碼是寫在DataContext中。

資料層:DataEntity <- DataMapper<DataEntity> <- DataContext

在這樣的資料層之上構建了“貌似”DDD的領域層,首先由領域物件繼承資料上下文以實現序列化和髒讀校驗等功能,聚合根又繼承領域物件以實現級聯更新、延遲載入和管理領域物件之間的關聯,最後由實現了LINQ查詢的倉儲物件管理聚合根,這就是當時的領域層。

領域層:DataContext <- Entity <-RootEntity <- Repository

這套架構陸陸續續用了1年左右,在運用的過程中發現DDD除了增加專案的複雜程度之外,沒有帶來任何好處,這是為什麼呢?

直到前段時間我才發現,構建在資料層之上的領域層完全就是一個錯誤,領域層應當處於整個專案中的最底層,而且完全不用繼承IEntity,IRepository之類的介面,正是這些介面綁架了領域模型。

==================分割線==================

經過重新設計的領域層今天終於完工了,處於最底層的仍舊是資料實體,原來的泛型DAO和DataContext全部都移動到了橫切層,以類似於切面的方式向領域層提供服務。

資料實體之上是值物件,值物件是完全按照領域需求構建的。資料實體和值物件之間還有一層薄薄的資料轉換服務,用於將面向資料庫的資料實體轉換為面向領域的值物件。

                    

資料層:DataEntity <-> Data Transformation Services <-> ValueObject

資料層之上是領域層,一個領域物件內持有若干個值物件,領域物件負載維護自生的狀態,和領域物件處於同一層次的是領域服務,領域服務更傾向與處理業務邏輯,在兩者之上有倉儲物件,僅負責查詢。

領域層:Entity / Service <- Repository

構建在資料層和領域層之外的是橫切層,橫切層提供輕量級的資料服務,例如事務管理、物件快取,單例模式的DataMapper。這些服務都是以using的方式提供,即:只能在小範圍的函式塊內使用,使用過後自動銷燬。

橫切層:EventManager / CacheManager / DataManager 等。

==================分割線==================

現在的領域層已經處於整個專案的最底層了,ValueObject完全是按照領域的物件的需求構建的,使用起來得心應手。

今天在一個大專案中實踐後發現,完全可以不參考UI設計,不參考原型設計,只按照需求說明書設計領域結構,設計完成之後的領域模型居然很神奇的符合UI和原型的需求。

這樣的開發流程似乎也很符合TDD的理念,介面先行、之後是測試、再後來是功能、最後才是UI。

相關文章