2010-04-21 60 views
48

我知道這可能是一個古老的問題,但什麼是更好的做法?在應用程序的所有層中使用域模型對象,甚至直接將值綁定到JSP上(我正在使用JSF)。或者將域模型對象轉換爲DAO或服務層中的DTO,並將輕量級DTO發送到表示層。視圖層中的DTO或域模型對象?

我被告知使用DTO是沒有意義的,因爲對數據庫的更改將導致所有DTO的更改,而到處使用模型對象只需要更改受影響的模型對象。但是,DTO的易用性和輕便性似乎超過了這一點。

我應該注意到我的應用程序使用Hibernate模型對象並使用自己的自定義創建的模型對象(意思是不綁定到任何數據庫會話,總是分離)。上述任何一種情況對於嚴格的模型對象模式都更有利?對於Lazy Initialization Exceptions這樣的事情來說,使用Hibernate是一個巨大的PITA。

我編輯的進一步討論,希望這個問題(不知道我這樣做是正確的):

我有一個模型對象的問題是,他們是不靈活的。下面的評論說應該設計應用程序,以便模型對象可以在所有層中使用。爲什麼?如果用戶想要一些荒謬的功能,我是否應該告訴他們,'這不適用於模型對象'?

簡單而簡單,有些時候模型對象不起作用。你可能有:

public class Teacher { 
    List<Student> students; 
    [tons of other Teacher-related fields] 
} 
public class Student { 
    double gpa; 
    [tons of other Student-related fields] 
} 

但也許你不需要所有的信息。你只需要老師的姓氏,他們今年教的學生人數,以及所有學生的平均GPA總和。在這種情況下你會做什麼?檢索完整的教師信息和學生關係,然後你的代碼在學生名單上計數,然後計算所有gpas的總平均數?這似乎比通過'String lastName','int numStudents'和'double combinedGpa'創建DTO更省力。

這可能聽起來像我的想法已經彌補了這些,但我還沒有在模型對象可以完全在每個實例中完全使用的應用程序中工作。普通的真實世界的應用程序不符合普通的用戶需求,但並不是那樣。

回答

30

一個明確的答案這真的取決於你的應用程序的複雜性。混合域對象到視圖層有兩種可能的含義:

  1. 你會被誘惑去修改你的域對象,以適應您的視圖層需要
  2. 您的視圖層將包含額外造成了複雜的事情您的域對象提供的內容與您的視圖真正需要的內容不匹配。您可能無法繞過這種複雜性,但它可能不屬於View層。

如果您的域對象很簡單並且您的視圖很少,那麼跳過DTO可能是最簡單的事情。另一方面,如果你的領域模型有可能演化並變得複雜,並且如果你的觀點可能是多種多樣的,那麼查看特定對象可能是一個好主意。在MVC世界中,使用ViewModels是很常見的,對我來說很有意義。

-4

DTO現在被廣泛認爲是反模式,建議通常是「不惜一切代價避免它們」。

像Hibernate這樣的ORM框架的主要優點之一就是你可以在所有級別使用域對象,並且不需要DTO。當然,需要注意的是,你必須花些時間來思考這些關係:何時使用懶惰提取,何時使用渴望等。

+0

是的,我明白了。它看起來好像有時會增加不必要的複雜性。如果我有一個表示老師的對象,並且有時候我只需要頭信息(姓名,地址),我必須發送一個半人口填充的域對象到前端。它只是一種誤導,似乎不正確的我。 – sma 2010-04-21 13:43:27

+4

@ smayers81 - 你爲什麼只在中途填充你的域對象?這聽起來像是一種不必要的優化(當然,如果你已經進行了配置或者發現了一個問題,那當然不會)這聽起來像你的問題的根源 - 對待你的域對象,如DTOs。爲什麼不把你的完全水合的域對象推到前端?如果你發現你有一個性能問題,那麼你有一個DTO的例子(或者完全繞過自定義對象,並直接處理你的框架提供的任何記錄集抽象)。 – 2010-04-28 16:41:54

+0

因爲我總是覺得,如果沒有真正需要,通過網絡發送所有數據。我認爲這是Hibernate的懶惰理念背後的全部動力(我可能在那裏錯了) – sma 2010-04-30 00:32:29

7

對域對象的另一投票。就領域驅動設計而言,領域模型是國王,應儘可能使用領域模型。應用程序的設計應該以大多數圖層(酒吧基礎設施層)可以使用域對象的方式進行。

我認爲DTOs只在對象需要序列化時纔有用。如果沒有通過線路傳輸或不兼容的架構,我不會使用它們。 DTO模式對保持序列化不在域對象中很有用。考慮到UI /域的交互不需要序列化,保持簡單並使用實際的對象。

+3

我認爲會話需要序列化集羣環境中的狀態管理?即使我們現在擁有的模型對象(休眠模型和定製的,分離的模型對象)都是可序列化的。 – sma 2010-04-21 13:40:32

+2

我不認爲他指的是你正在談論的序列化(a-la Serializable)。我認爲他的意思是序列化XML,JSON,AMF(Flex),CSV等等。 – Aquarelle 2013-04-10 06:08:29

2

方案時域對象是有問題的要被髮送:

  1. 可能需要聚集的信息或其它類型的「計算字段」發送到UI層(在示例的Flex/GWT)的和不希望亂域對象
  2. 你可能會遇到需要序列化循環對象圖(在你的榜樣,如果學生有列表關係),與框架序列化處理(BlazeDS的用於當一些協議具有與
  3. Hibernate的LazyInitializationException中的問題flex/GWT串行器)

我不知道它在那些cirumcstances

7

我認爲DTO並不是一般的反模式。有很多人和使用它們的系統,您獲得的好處是可以獨立於域模型進行設計和模塊化的解耦視圖層。雖然我同意你應該儘可能使用域對象,但是當你將視圖層直接綁定到域模型時,有些情況下你可能會遇到問題。

我對視圖模型做了很好的體驗,它只包含域對象並將大部分操作委託給它們。這樣可以解耦視圖和域圖層,允許靈活組合域對象,並且不需要太多工作因爲IDE支持委託模式。

1

在我看來,在每個圖層中使用域模型對象都沒有問題。你說你不需要所有的信息。當你在JSP中時,只使用你需要的數據。沒有人強迫你拿取每一個財產。你還說你需要進行與對象屬性相關的計算才能獲得GPA,學生數量等等。你有3個選擇:在你的領域模型對象中創建綜合屬性,爲你返回正確的數據,包裝好整齊;在控制器或服務層中執行計算,並通過適當的獲得者來公開它們;或者在你的JSP中處理它。您需要檢索/編譯/纏繞數據ANYWAY,所以爲什麼要增加DTO的複雜性。 (DTO),工廠方法(DAO),工廠方法(DAO)等)。 6個月後,更多的維護=開心的開發者。

所以,我的論點反對DTOs。我確實使用它們,但只在某些情況下,比如當我真的需要針對速度和/或內存使用進行優化時,保護完整域模型對象的成本太高。當我更喜歡使用DTO時,Web服務就是一個很好的例子。

-1

我認爲我們首先應該考慮的是引入新層的成本。以DTO爲例 - 這樣做我們需要一個映射。正如有人所說,翻譯是邪惡的,應儘可能避免。

另一方面,我認爲你通常不應該做的事情很少。那些說所有DTO是邪惡的人都是錯誤的 - 它總是取決於用例!他們真的有道理嗎?

最後,我個人認爲域對象應該放到視圖本身。想象一下,Wicket集成是什麼樣子。但以Spring MVC爲例 - 域可能會留在應用程序層中,可能...

0

類或其內部方法的行爲不應暴露給與其行爲無關的層。傳輸數據,而不是行爲。使用域內的域對象。網絡不是一個受控制的域,UI開發人員不需要關心域行爲,只需要關注數據。

該域名必須被封裝,並且不得被不關心該域名健康的人修改。

泄漏行爲並不是最好的習慣。

如果是一個小項目,也可以使用正確的principes構建它。這樣我們總是記住我們爲什麼要做我們所做的事情,而不是如何做。