在項目應用中器联,VO對應于頁面上需要顯示的數(shù)據(jù)(表單),DO對應于數(shù)據(jù)庫中存儲的數(shù)據(jù)(數(shù)據(jù)表)婿崭,DTO對應于除二者之外需要進行傳遞的數(shù)據(jù)主籍。
一、實體類
百度百科中對于實體類的定義如下:
實體類的主要職責是存儲和管理系統(tǒng)內(nèi)部的信息逛球,它也可以有行為,甚至很復雜的行為苫昌,但這些行為必須與它所代表的實體對象密切相關颤绕。
根據(jù)以上定義,我們可以了解到祟身,實體類有兩方面內(nèi)容奥务,存儲數(shù)據(jù)和執(zhí)行數(shù)據(jù)本身相關的操作。這兩方面內(nèi)容對應到實現(xiàn)上袜硫,最簡單的實體類是POJO類氯葬,含有屬性及屬性對應的set和get方法,實體類常見的方法還有用于輸出自身數(shù)據(jù)的toString方法婉陷。
二帚称、領域模型中的實體類
領域模型中的實體類分為四種類型:VO官研、DTO、DO闯睹、PO戏羽,各種實體類用于不同業(yè)務層次間的交互,并會在層次內(nèi)實現(xiàn)實體類之間的轉化楼吃。
業(yè)務分層為:視圖層(VIEW+ACTION)始花,服務層(SERVICE),持久層(DAO)
概念:
VO(View Object):視圖對象孩锡,用于展示層酷宵,它的作用是把某個指定頁面(或組件)的所有數(shù)據(jù)封裝起來。
DTO(Data Transfer Object):數(shù)據(jù)傳輸對象躬窜,這個概念來源于J2EE的設計模式浇垦,原來的目的是為了EJB的分布式應用提供粗粒度的數(shù)據(jù)實體,以減少分布式調(diào)用的次數(shù)斩披,從而提高分布式調(diào)用的性能和降低網(wǎng)絡負載溜族,但在這里,我泛指用于展示層與服務層之間的數(shù)據(jù)傳輸對象垦沉。
DO(Domain Object):領域對象煌抒,就是從現(xiàn)實世界中抽象出來的有形或無形的業(yè)務實體。
PO(Persistent Object):持久化對象厕倍,它跟持久層(通常是關系型數(shù)據(jù)庫)的數(shù)據(jù)結構形成一一對應的映射關系寡壮,如果持久層是關系型數(shù)據(jù)庫,那么讹弯,數(shù)據(jù)表中的每個字段(或若干個)就對應PO的一個(或若干個)屬性况既。
模型:
??????下面以一個時序圖建立簡單模型來描述上述對象在三層架構應用中的位置
? ? ? ? 用戶發(fā)出請求(可能是填寫表單),表單的數(shù)據(jù)在展示層被匹配為VO组民。
? ? ? ? 展示層把VO轉換為服務層對應方法所要求的DTO棒仍,傳送給服務層。
? ? ? ?服務層首先根據(jù)DTO的數(shù)據(jù)構造(或重建)一個DO臭胜,調(diào)用DO的業(yè)務方法完成具體業(yè)務莫其。
? ? ? ?服務層把DO轉換為持久層對應的PO(可以使用ORM工具,也可以不用)耸三,調(diào)用持久層的持久化方法乱陡,把PO傳遞給它,完成持久化操作仪壮。
? ? ? ?對于一個逆向操作憨颠,如讀取數(shù)據(jù),也是用類似的方式轉換和傳遞积锅,略爽彤。
三养盗、應用與區(qū)別
VO與DTO的區(qū)別
DTO代表服務層需要接收的數(shù)據(jù)和返回的數(shù)據(jù),而VO代表展示層需要顯示的數(shù)據(jù)淫茵。
VO與DTO的應用
? ? ? ? ?當需求非常清晰穩(wěn)定爪瓜,而且客戶端很明確只有一個的時候,沒有必要把VO和DTO區(qū)分開來匙瘪,這時候VO可以退隱铆铆,用一個DTO即可,為什么是VO退隱而不是DTO丹喻?回到設計層面难捌,服務層的職責依然不應該與展示層耦合而晒,所以姨谷,對于前面的例子赐劣,你很容易理解,DTO對于“性別”來說鳍悠,依然不能用“帥哥美女”税娜,這個轉換應該依賴于頁面的腳本(如JavaScript)或其他機制(JSTL、EL藏研、CSS)
? ? ? ? 即使客戶端可以進行定制敬矩,或者存在多個不同的客戶端,如果客戶端能夠用某種技術(腳本或其他機制)實現(xiàn)轉換蠢挡,同樣可以讓VO退隱
DTO與DO的區(qū)別
? ? ? ? 首先是概念上的區(qū)別弧岳,DTO是View層和Service層之間的數(shù)據(jù)傳輸對象(可以認為是兩者之間的協(xié)議),而DO是對現(xiàn)實世界各種業(yè)務角色的抽象业踏,這就引出了兩者在數(shù)據(jù)上的區(qū)別.
DTO與DO的應用
? ? ? ?在設計層面禽炬,View層向Service層傳遞的DTO與Service層返回給View層的DTO在概念上是不同的,但在實現(xiàn)層面勤家,我們通常很少會這樣做(定義兩個UserInfo腹尖,甚至更多),因為這樣做并不見得很明智伐脖,我們完全可以設計一個完全兼容的DTO热幔,在服務層接收數(shù)據(jù)的時候,不該由View層設置的屬性(如訂單的總價應該由其單價晓殊、數(shù)量、折扣等決定)伤提,無論View層是否設置巫俺,Service層都一概忽略,而在Service層返回數(shù)據(jù)時肿男,不該返回的數(shù)據(jù)(如用戶密碼)介汹,就不設置對應的屬性却嗡。
? ? ? 兩者在本質(zhì)上的區(qū)別可能導致彼此并不一一對應,一個DTO可能對應多個DO嘹承,反之亦然窗价,甚至兩者存在多對多的關系。
? ? ? DO具有一些不應該讓View層知道的數(shù)據(jù) DO具有業(yè)務方法叹卷,如果直接把DO傳遞給View層撼港,View層的代碼就可以繞過Service層直接調(diào)用它不應該訪問的操作,對于基于AOP攔截Service層來進行訪問控制的機制來說骤竹,這問題尤為突出帝牡,而在View層調(diào)用DO的業(yè)務方法也會因為事務的問題,讓事務難以控制蒙揣。
? ? ?對于某些ORM框架(如hibernate)來說靶溜,通常會使用“延遲加載”技術,如果直接把DO暴露給View層懒震,對于大部分情況罩息,View層不在事務范圍之內(nèi)(Open session in view在大部分情況下不是一種值得推崇的設計),如果其嘗試在Session關閉的情況下獲取一個未加載的關聯(lián)對象个扰,會出現(xiàn)運行時異常(對于Hibernate來說瓷炮,就是LazyInitiliaztionException)。
? ? ? 從設計層面來說锨匆,View層依賴于Service層崭别,Service層依賴于領域層,如果把DO暴露出去恐锣,就會導致View層直接依賴于dao層茅主,這雖然依然是單向依賴,但這種跨層依賴會導致不必要的耦合土榴。