前言
在項目開發中,是否需要定義VO(視圖對象),BO(業務對象),PO(持久化對象),DO(領域對象),DTO(數據傳輸對象)取決于項目的規模、復雜性、團隊的協作方式以及項目的長遠規劃。
對于小型或者簡單的項目,如果團隊成員較少,項目需求穩定且迭代速度不是很快,確實可以不嚴格區分這些對象,使用簡單的POJO(Plain Old Java Object)
來進行各層之間的數據傳遞。這樣做可以減少項目的復雜度,加快開發進度。
然而,對于大型或復雜的項目,尤其是那些需要長期迭代和維護的,以及參與人員較多的項目,定義這些不同的對象有其必要性:
- VO(視圖對象):它們用于前端展示,可以屏蔽后端數據結構的變化對前端的影響,有助于保持前后端的分離和松耦合。
- DTO(數據傳輸對象):在服務層和展示層之間傳輸數據時使用,它們可以減少網絡傳輸的數據量,提高性能,并且可以在不同層次之間提供一個清晰的界限。
- BO(業務對象):封裝了業務邏輯,可以提高代碼的復用性,使得業務邏輯更加清晰,易于維護。
- PO(持久化對象):它們與數據庫結構直接對應,有助于實現數據訪問層的封裝,降低持久化邏輯與業務邏輯的耦合。
- DO(領域對象):它們代表業務領域的概念,有助于構建領域模型,促進開發人員與業務專家之間的溝通。
易混點一:VO和DTO
首先VO是最常用的,但對于這個概念,網上也是眾說紛紜,value object 或 view object,一般說視圖對象或者值對象,我更傾向理解為視圖對象。說白了它就是展示用的,不管展示方式是網頁,還是客戶端,還是APP,只要是這個東西是讓人看到的,我們就把它封裝為VO。
VO比較容易混淆的是DTO,DTO是展示層與服務層之間傳遞數據的對象,可以這樣說,對于絕大部分的應用場景來說,DTO和VO的屬性值基本是一致的,而且他們通常都是POJO,那么既然有了VO,為什么還需要DTO呢?
我們舉例來說明一下:
某公司有一個后臺服務,服務層有一個getUser的方法返回一個系統用戶,包含sex(性別)、年齡。對于服務層來說,DTO只從語義上定義,可能是這樣的:
{"gender":"男","age":35
}
但這個服務同時供多個客戶端使用(不同門戶),而不同的客戶端對于表現層的要求有所不同,比如管理端要求顯示準確的年齡,而應用端為了保護客戶隱私,只需要顯示一個年齡段即可。
管理端VO:
{"gender":"男","age":35
}
應用端VO:
{"gender":"男","age":30~40
}
從這個例子可以看出,DTO很有存在的必要,根據職責單一原則,服務層只負責業務,與具體的表現形式無關,DTO不應該出現與表現形式的耦合,DTO定義的是原始數據,VO再對DTO數據進行解釋。這下VO和DTO用法就清晰很多了。
職責單一原則(Single Responsibility Principle, SRP)是面向對象設計中的一個重要原則,由Robert C. Martin提出。該原則指出,任何一個軟件單元(如類、模塊或服務)都應當有且只有一個引起其變化的原因。這個原則的核心理念是提高代碼的內聚性,降低耦合性,使代碼更易于理解和維護。
易混點二:BO和PO
PO是持久對象,這個很好理解,就是實體和數據庫字段的對應,一個PO的數據結構對應著庫中表的結構,表中的一條記錄就是一個PO屬性,大多數情況下,PO僅僅作為PO只是用來增刪改使用。
PO比較容易混淆的是BO,BO是業務對象,對應的是某個具體的業務塊,可以包含多個屬性、對象。簡單點來說,我們可以把BO看作是PO的組合。
我們舉例來說明一下:
PO-1是交易記錄對象,PO-2是登錄記錄對象,PO-3是商品瀏覽記錄對象,PO-4是添加購物車記錄對象,PO-5是搜索記錄對象,BO是個人網站行為對象,BO對象:{PO-1;PO-2;PO-3;PO-4;PO-5}。這樣做的優點不言而喻,維護代碼的時候查看BO,就能知道這塊邏輯涉及多少表(PO)。
易混點三:BO和DTO
搞清楚了BO和PO各自的用途后,我們會發現BO和DTO有重疊功能,一樣可以對PO進行排列組合,那BO的存在的意義是什么呢?
從用途上進行根本的區別,BO是業務對象,DTO是數據傳輸對象,雖然BO也可以排列組合數據,但它的功能是對內的,比如上個例子中的BO對象包括{PO-1;PO-2;PO-3;PO-4;PO-5}還有其他字段屬性,但在提供對外接口時,BO對象中的某些屬性對象可能用不到或者不方便對外暴露,那么此時DTO只需要在BO的基礎上,抽取自己需要的數據,然后對外提供。
在這個關系上,通常不會有數據內容的變化,內容變化要么在BO內部業務計算的時候完成,要么在解釋VO的時候完成。
DO
DO是領域對象,就是從現實世界中抽象出來的有形或無形的業務實體。事實上,DO和PO在絕大部分情況下是一一對應的。阿里巴巴的開發手冊中的定義DO等同于PO,即與數據庫表結構一一對應,通過DAO層向上傳輸數據源對象。
上一張圖,更加直觀的展示這些名詞使用的節點:
總結
VO,BO,PO,DTO這樣分層還是很有意義的。尤其在團隊成員較多的情況下,結構更加一目了然,同時也能很大程度避免多端系統數據所需不一致時,有人修改屬性影響其他頁面。但也完全沒有必要教條主義,把這些全部用上,需要根據所開發的業務復雜度來取舍,如果本身業務邏輯不負責,照搬全上反而讓開發變的更復雜。
例如業務不復雜,根本沒有多端展示的差異化,VO可以直接拿掉,直接使用DTO傳輸到前端數據即可。
同時在使用過程中,最重要的是要在團隊中達成共識,概念一致,如果使用了這些,但各按各的理解來,甚至抓起來就直接用,反而會讓代碼變得更亂,還不如直接POJO、DTO打天下。
另附這些概念命名規范:
- 數據對象:xxxPO,xxx即為數據表名。(也可DO)
- 數據傳輸對象:xxxDTO,xxx為業務領域相關的名稱。
- 展示對象:xxxVO,xxx一般為網頁名稱。
- 業務對象:xxxBO,xxx是業務名稱。
本文參考自Java知音。1
https://mp.weixin.qq.com/s/3-wA3hh75pgoTJu0Rz3SXw ??