談談我對實體的認識:DTO,DMO,DPO

今天和大家談的是我對於實體的一些認識,難免有偏頗之初,還請各位指出。

 

大家都看到標題中的三個英文縮寫了:DTO,DMO,DPO。DTO大家應該還是熟悉的,Data Transfer Ojbect(數據傳輸對象)。研究過DDD(Domain Driven Design領域驅動設計)的人應該瞭解過DTO。是用來傳輸數據的對象,應爲領域對象雖然有數據(屬性),但是領域對象上面還帶有操作,在某些場合不適合進行傳輸,因爲有些時候傳輸還需要序列化,而且也不是所有的領域對象屬性都可以暴露給調用端的,而且有些屬性可能要合併,可能要分解,之後才有利於調用端的使用,加上其他一些的業務原因,於是就有了專門用來傳輸數據的DTO,只有屬性,沒有操作,必要的時候加上序列化標記,實現遠程調用。

 

DMO和DPO是我自己創造的名詞,在後面再解釋給大家聽。

 

剛開始看到別人用來表達數據對象的類的時候,都是隻有屬性,沒有操作,而且大都是和數據庫表一一對應的。可以單獨建立一個項目,名字叫做Project.Entity。在獨立的一個項目中保存所有用到的實體,其他的項目添加對Project.Entity項目的引用。

entity1

 

就拿User舉個例子吧。

public class User
{
    public Guid UserID { get; set; }

    public string Username { get; set; }
}

也有人喜歡在實體類添加後綴,方便標識,因爲有可能領域對象也叫做User,但是覺得都叫做User又有點彆扭,不好區分。就像分層的話,可能會有UserBll,UserDal之類的類產生。(在這裏不討論這些類是否合適,只是說明這種現象,但是如果大家有這方面的好思路,也可以分享一下)

 

然後不管是添加還是修改,還是查詢顯示,都是用這個User實體。這個在做ASP.NET或者WinForm的時候還可以。反正客戶端和服務端都可以引用這個類庫,不影響開發。

 

有一點,我個人比較喜歡將一些查詢條件作爲一個實體的屬性。這樣查詢方法就不需要很多參數了,只有一個實體作爲參數就可以了。而且在後面如果條件有變化,只要在實體添加屬性,方法的內部添加或者刪除參數的處理就可以了。至少調用端不用做任何修改。如果每個添加都作爲一個參數的話,增加或者刪除參數,服務端修改方法,調用端就需要修改調用的地方。也能減少一些開發工作吧,而且在界面的查詢條件很多的時候,不至於查詢方法的參數列表也很長。

例如用戶查詢,我就會建立一個UserFind實體。下面的例子中說明界面有兩個條件,一個是用戶姓名,一個是註冊時間。

    public  class UserFind
    {
        public string Username { get; set; }

        public DateTime RegDate { get; set; }

        
    }

 

問題1

產生的問題就是添加的時候肯定是每個屬性都要添加到數據庫,修改的時候,有些屬性不用或者是不能修改,允許部分的修改。還有就是顯示的時候,可能還需要其他的屬性,例如User實體下面可能會有一些集合屬性,例如用戶全部地址,郵件個數,是否有新郵件,是否有新訂單之類的需求,就要在User實體添加其他屬性。但是這些屬性在添加和修改的時候都用不到。如果這幾種情況還是共享一個實體的話,容易引起誤用。而且增加溝通,需要告訴做添加功能的人,你只要添加屬性1,2,3就可以了。告訴做顯示的人,你需要每個屬性都賦值。告訴做修改的人,屬性2,3,4,5是可以修改的。

 

還有那個查詢實體,例如查詢訂單吧。用戶查詢訂單,只能查詢自己的訂單。

    public class OrderFind
    {
        public string OrderSeqNo { get; set; }

        public DateTime PlaceDate { get; set; }
    }


根據訂單編號和下單時間查詢。

可是後臺查詢用戶訂單的時候,可能會需要用戶的信息,例如查詢姓名爲“張三”的訂單。好吧,修改這個查詢實體。

    public class OrderFind
    {
        public string OrderSeqNo { get; set; }

        public DateTime PlaceDate { get; set; }

        public string Username { get; set; }
    }

問題2

同樣,這就需要在開發用戶查詢訂單的時候忽略Username屬性,在開發後臺查詢訂單的時候加上Username屬性。

是不是這兩個功能也應該區分一下呢?

於是我就有了下面的總結。

1、實體的專用性

1) 儘量的保持實體的專用性,也就是一個功能的方法,雖然和兩外一個方法的返回結果類似,可能只需要添加一兩個屬性,這樣的情況,重新建立實體,方便後面可能對這兩個方法返回內容的修改不至於相互影響。

2) 儘量保持一個實體中的每一個屬性,每一個被賦值的屬性,將來都會用到,否則減少實體的屬性,或者新建一個實體,使用正好合適的屬性個數。

3) 分離添加和顯示用的實體,因爲添加可能不是每個字段都需要賦值,或者一些值是默認值。

4) 分離不同類型的用戶使用的實體,儘管是相同的功能。可以在類名添加ForPlanter之類的後綴來解決。因爲不同用戶關注的點不同,關注的屬性肯定不相同。而且修改也不影響其他類型用戶的使用。

最近的一個項目是WCF+Silverlight。一個類庫項目不行了,需要添加兩個類庫項目,因爲Silverlight不能添加普通類庫引用,Silverlight有自己的類庫項目模板。

當然了,實體的代碼還是可以共享的,但是類庫必須是兩個。

 

在簡單學習了DDD之後,發現裏面的一個概念叫做DTO,數據傳輸對象。覺得其他和我的Project.Entity項目比較像,反正功能都是用來承載數據,不帶有任何操作。甚至連數據驗證都沒有,數據驗證可以通過attribute,集合獨立的模塊來完成。

 

問題2已經有了解決方案,就是保持實體的專用,減少混用。

 

可是問題1呢?

後來我們想減少代碼的開發量,尤其是在增、刪、改、查的數據庫操作方面,想要引進一些工具類庫,來幫助我們完成數據庫的操作,使得我們可以專注於業務方面的開發。

這方面的類庫有很多,例如:NHibernate,還有微軟的Entity Framework等。引入這些時候我發現問題1變得更加突出了。要不然就會有大量的冗餘字段被讀取,甚至被網絡傳輸(WCF+Silverlight的數據需要經過網絡,SOAP消息的形式傳輸到客戶端)。

 

於是DTO,DPO,DMP就產生了。

1、傳輸實體,經過客戶端傳輸給wcf。在服務端可能需要組合產生新的數據庫持久化實體(區分添加用實體和更新用實體),這些實體經過ORM將數據持久化到數據庫。

2、從數據庫查詢的數據,經過ORM映射產生的實體,然後經過處理,產生傳輸實體,傳輸給客戶端。

3、數據傳輸實體dto,數據庫持久化實體dpo,數據庫映射實體dmo

Technorati 標籤: DTO,DPO,DMO,DDD
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章