數據傳輸對象(DTOs)
數據傳輸對象(Data Transfer Objects)用于應用層和展現層的數據傳輸。
展現層傳入數據傳輸對象(DTO)調用一個應用服務方法,接著應用服務通過領域對象執行一些特定的業務邏輯并且返回DTO給展現層。這樣展現層和領域層被完全分離開了。在具有良好分層的應用程序中,展現層不會直接使用領域對象(倉庫,實體)。
1.數據傳輸對象的作用:
為每個應用服務方法創建DTO看起來是一項乏味耗時的工作。但如果你正確使用它們,這將會解救你的項目。為啥呢?
(1)抽象領域層 (Abstraction of domain layer)
在展現層中數據傳輸對象對領域對象進行了有效的抽象。這樣你的層(layers)將被恰當的隔離開來。甚至當你想要完全替換展現層時,你還可以繼續使用已經存在的應用層和領域層。反之,你可以重寫領域層,修改數據庫結構,實體和ORM框架,但并不需要對展現層做任何修改,只要你的應用層沒有發生改變。
(2)數據隱藏 (Data hiding)
想象一下,你有一個User實體擁有屬性Id, Name, EmailAddress和Password。如果UserAppService的GetAllUsers()方法的返回值類型為List。這樣任何人都可以查看所有人的密碼,即使你沒有將它打印在屏幕上。這不僅僅是安全問題,這還跟數據隱藏有關。應用服務應只返回展現層所需要的,不多不少剛剛好。
(3)序列化 & 惰性加載 (Serialization & lazy load problems)
當你將數據(對象)返回給展現層時,數據有可能會被序列化。舉個例子,在一個返回Json的MVC的Action中,你的對象需要被序列化成JSON并發送給客戶端。直接返回實體給展現層將有可能會出現麻煩。
在真實的項目中,實體會引用其他實體。User實體會引用Role實體。所以,當你序列化User時,Role也將被序列化。而且Role還擁有一個List并且Permission還引用了PermissionGroup等等….你能想象這些對象都將被序列化嗎?這有很有可能使整個數據庫數據意外的被序列化。那么該如何解決呢?將屬性標記為不可序列化?不行,因為你不知道屬性何時該被序列化何時不該序列化。所以在這種情況下,返回一個可安全序列化,特別定制的數據傳輸對象是不錯的選擇哦。
幾乎所有的ORM框架都支持惰性加載。只有當你需要加載實體時它才會被加載。比如User類型引用Role類型。當你從數據庫獲取User時,Role屬性并沒有被填充。當你第一次讀取Role屬性時,才會從數據庫中加載Role。所以,當你返回這樣一個實體給展現層時,很容易引起副作用(從數據庫中加載)。如果序列化工具讀取實體,它將會遞歸地讀取所有屬性,這樣你的整個數據庫都將會被讀取。
在展現層中使用實體還會有更多的問題。最佳的方案就是展現層不應該引用任何包含領域層的程序集。
新聞熱點
疑難解答
圖片精選