VO、DTO、DO、PO
淺析VO、DTO、DO、PO
概念
具體區別&應用
VO與DTO的區別
大家可能會有個疑問:既然DTO是展示層與服務層之間傳遞數據的對象,為什么還需要一個VO呢?對!對于絕大部分的應用場景來說,DTO和VO的屬性值基本是一致的,而且他們通常都是POJO,因此沒必要多此一舉。但不要忘記這是實現層面的思維,對于設計層面來說,概念上還是應該存在VO和DTO,因為兩者有著本質的區別,DTO代表服務層需要接收的數據和返回的數據,而VO代表展示層需要顯示的數據。
舉個例子
:例如服務層有一個getUser的方法返回一個系統用戶,其中有一個屬性是gender(性別),對于服務層來說,它只從語義上定義:1-男性,2-女性,0-未指定,而對于展示層來說,它可能需要用“帥哥”代表男性,用“美女”代表女性,用“秘密”代表未指定。說到這里,可能你還會反駁,在服務層直接就返回“帥哥美女”不就行了嗎?對于大部分應用來說,這不是問題,但設想一下,如果需求允許客戶可以定制風格,而不同風格對于“性別”的表現方式不一樣,又或者這個服務同時供多個客戶端使用(不同門戶),而不同的客戶端對于表現層的要求有所不同,那么,問題就來了。再者,回到設計層面上分析,從職責單一原則來看,服務層只負責業務,與具體的表現形式無關,因此,它返回的DTO,不應該出現與表現形式的耦合。
VO與DTO的應用
為什么不在服務層中直接返回DO呢?這樣可以省去DTO的編碼和轉換工作,原因如下:
DTO應該是一個“扁平的二維對象”,舉個例子來說明:如果User會關聯若干個其他實體(例如Address、Account、Region等),那么getUser()返回的UserInfo,是否就需要把其關聯的對象的DTO都一并返回呢?如果這樣的話,必然導致數據傳輸量的大增,對于分布式應用來說,由于涉及數據在網絡上的傳輸、序列化和反序列化,這種設計更不可接受。如果getUser除了要返回User的基本信息外,還需要返回一個AccountId、AccountName、RegionId、RegionName,那么,請把這些屬性定義到UserInfo中,把一個“立體”的對象樹“壓扁”成一個“扁平的二維對象”。
這里說的非常好,DTO和DO交互時,或者DTO直接和PO交互時,DO和PO中非常多的字段,DTO是不使用的,不應該全部帶過來,只需要把DO和PO中需要的字段Copy到DTO中,然后再進行轉換。有的同學為了圖方便,DTO是直接繼承PO或者DO(我之前就這個干過),然后DTO又和PO的字段是一致的,導致通過PO吐出的字段超級多,數據傳輸大不說,關鍵是接口輸出時,一大坨字段,抓不住重點。
DO與PO的區別
DO和PO在絕大部分情況下是一一對應的,PO是只含有get/set方法的POJO,但某些場景還是能反映出兩者在概念上存在本質的區別:
舉兩個例子:客戶Customer有其聯系信息Contacts,這里是兩個一對一關系的DO,但可能出于性能的考慮(極端情況,權作舉例),為了減少數據庫的連接查詢操作,把Customer和Contacts兩個DO數據合并到一張數據表中。反過來,“角色”與“資源”之間存在多對多關系,會存放到多張表中,而這種關系很明顯會表現為一個DO——“權限”。
- PO的某些屬性值對于DO沒有任何意義,這些屬性值可能是為了解決某些持久化策略而存在的數據,例如為了實現“樂觀鎖”,PO存在一個version的屬性,這個version對于DO來說是沒有任何業務意義的,它不應該在DO中存在。同理,DO中也可能存在不需要持久化的屬性。
總結:DO和PO是兩個層級的概念,兩者存在一對一、一對多和多對一的關系。這兩個層級的字段,DO不需要包括全部的PO,比如PO中的創建、刪除標記、自動生成的ID等,PO可以不用關注。
總結
以上是生活随笔為你收集整理的VO、DTO、DO、PO的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数码视讯Q5刷armbian+squee
- 下一篇: VO、DTO、BO、PO、DO、POJO