深扒Java中POJO、VO、DO、DTO、PO、BO、AO、DAO的概念和區(qū)別以及如何應(yīng)用
一. 前言
POJO、VO、DO、DTO、PO、BO、AO 和 DAO 等術(shù)語被廣泛應(yīng)用于各種編程語言中。盡管這些術(shù)語是非常常見的,但是很多程序員依然無法清楚地理解它們之間的區(qū)別和關(guān)系。本文將深入探討這些術(shù)語的含義和用途,幫助程序員更好地理解它們之間的差異和聯(lián)系。
二. 概念
2.1. 概要介紹
- POJO(Plain Ordinary Java Object):簡單 Java 對象。
- VO(View Object or Value Object):視圖對象或值對象,用于展示層。
- DTO(Data Transfer Object):數(shù)據(jù)傳輸對象,泛指用于展示層與服務(wù)層之間的數(shù)據(jù)傳輸對象。
- PO(Persistent Object):持久化對象,它跟持久層(通常是關(guān)系型數(shù)據(jù)庫)的數(shù)據(jù)結(jié)構(gòu)形成一一對應(yīng)的映射關(guān)系。
- BO(Business Object):業(yè)務(wù)對象。封裝基本業(yè)務(wù)操作。
- DO(Data Object or Domain Object):數(shù)據(jù)對象或領(lǐng)域?qū)ο?,就是從現(xiàn)實(shí)世界中抽象出來的有形或無形的業(yè)務(wù)實(shí)體。
- AO(Application Object):應(yīng)用對象。
- DAO(Data Access Object):數(shù)據(jù)訪問對象。主要封裝對數(shù)據(jù)庫的訪問。
2.2. POJO(Plain Old/Ordinary Java Object)
簡單 Java 對象,表示一個(gè)個(gè)簡單的 Java 對象,POJO 是 DO、DTO、BO、VO 的統(tǒng)稱,禁止命名成 xxxPOJO。
使用 POJO 名稱是為了避免和 EJB 混淆起來,而且簡稱比較直接。其中有一些屬性及其 getter、setter 方法的類,沒有業(yè)務(wù)邏輯??梢哉f POJO 是一個(gè)JavaBean,但 JavaBean 不一定是 POJO。
2.3. VO(View/Value Object)
VO 對象全稱為 View Object(視圖對象)或者 Value Object(值對象),主要用于前端界面顯示的數(shù)據(jù),是與前端進(jìn)行交互的對象,但這里是不用 PO 傳遞數(shù)據(jù)的,因?yàn)?PO 包括數(shù)據(jù)庫表中的所有字段,對于前端來說我們只需要顯示一部分字段就可以了,例如我們的用戶表 user 中的 password(密碼)字段、phone(電話)字段、insert_time(插入時(shí)間)字段是沒有必要也不能顯示在前端界面的。遵循 JavaBean 規(guī)范,擁有 get 和 set 方法。
2.4. DTO(Data Transfer Object)
數(shù)據(jù)傳輸對象是在傳遞給前端時(shí)使用的,如一張表有100個(gè)字段,那么對應(yīng)的 PO 就有100個(gè)屬性,但是我們的前端界面只需要顯示10個(gè)字段,所以我們沒必要把所有字段的 PO 對象傳遞到客戶端,我們只需要把只有這10個(gè)屬性的 DTO 對象傳遞到客戶端,不會(huì)暴露服務(wù)端的表結(jié)構(gòu),到達(dá)客戶端后,如果這個(gè)對象用于界面表示,那么它的身份就是 VO 對象。
DTO 和 VO 概念相似,通常情況下字段也基本一致。但有所不同,DTO 表示一個(gè)數(shù)據(jù)傳輸對象,是在服務(wù)端用于不同服務(wù)或不同層之間的數(shù)據(jù)傳輸,例如,Dao 層到 Service 層,Service 層到 Web 層;而 VO 是在客戶端瀏覽器顯示的表現(xiàn)對象,用于在瀏覽器界面數(shù)據(jù)的顯示。
數(shù)據(jù)傳輸對象比較特殊,之所以將 DTO 繪制在 視圖層 和 業(yè)務(wù)邏輯層 之間,是因?yàn)樗袃煞N存在形式:
- 前端:它是以 Json 字串的形式存在。
- 后端:它是以對象的形式存在。
微服務(wù)之間 DTO 對象的模型鑒定形式:
- 服務(wù)(模塊)與服務(wù)(模塊)之間相對獨(dú)立,我們可以將數(shù)據(jù)傳輸對象命名為 DTO。
- 服務(wù)(模塊)與服務(wù)(模塊)之間不是獨(dú)立,每一個(gè)都不是一個(gè)完整的業(yè)務(wù)模塊,拆分可能僅僅是因?yàn)橛?jì)算復(fù)雜度或者性能問題考慮拆分的問題,那么就不能將對象命名為 DTO,只能是 BO。
2.5. PO(Persistent Object)
PO 對象全稱為 Persistent Object(持久化對象),用于表示數(shù)據(jù)庫中的一條記錄映射成的對象,類中應(yīng)該都是基本數(shù)據(jù)類型和 String,而不是更復(fù)雜的類型,因?yàn)橐蛿?shù)據(jù)庫表字段對應(yīng)。PO 僅僅用于表示數(shù)據(jù),不對數(shù)據(jù)進(jìn)行操作,擁有 get 和 set 方法。對象類中的屬性對應(yīng)數(shù)據(jù)庫表中的字段,有多少個(gè)字段就有多少個(gè)屬性,完全匹配。遵循 JavaBean 規(guī)范,擁有 get 和 set 方法。如下圖所示:
2.6. BO(Business Object)
BO 是實(shí)際的業(yè)務(wù)對象,會(huì)參與業(yè)務(wù)邏輯的處理操作,里面可能會(huì)包含多個(gè)類,用于表示一個(gè)業(yè)務(wù)對象。例如:用戶可以擁有寵物,在這里把用戶對應(yīng)一個(gè) PO、寵物對應(yīng)一個(gè) PO,那么建立一個(gè)對應(yīng)的 BO 對象來處理用戶和寵物的關(guān)系,每個(gè) BO 都包含用戶 PO 和寵物 PO,而處理邏輯時(shí)針對 BO 去處理。遵循 JavaBean 規(guī)范,擁有 get 和 set 方法。注:User 和 Pet 都是 PO 對象,但會(huì)放進(jìn) BO 中,形成一個(gè)復(fù)雜的業(yè)務(wù)對象。
2.7. DO(Data/Domain Object)
DO 對象全稱為 Data Object(數(shù)據(jù)對象)或者 Domain Object(領(lǐng)域?qū)ο螅?/strong>,也有一種叫法是 Entity Object,一般不推薦使用 Entity Object 這個(gè)叫法。該對象與數(shù)據(jù)庫表結(jié)構(gòu)一一對應(yīng),通過Dao 層向上傳輸數(shù)據(jù)對象,屬性和 PO 中的基本一致,用到的不多。
DO 用到的不多,有一種情況是微服務(wù)之間互相傳輸對象數(shù)據(jù)的時(shí)候,我們會(huì)將該數(shù)據(jù)抽取出來。
比如商品下單以后,大量的 JSON 數(shù)據(jù)會(huì)傳輸?shù)胶笈_(tái),我們會(huì)在后臺(tái)調(diào)用很多模塊,比如 OMS/訂單管理模塊,又或是 ERP 模塊,又或是 WMS/庫存物流模塊等,會(huì)調(diào)用很多其他微服務(wù)模塊。不同服務(wù)之間傳輸對象,就可以將對象定義為 DO 或者 TO(Transfer Object),不同叫法而已。然后兩個(gè)模塊之間 RPC 調(diào)用,傳輸?shù)膶ο笠粌蓚€(gè)模塊共享,一種是將每一個(gè)模塊涉及的各種實(shí)體對象單獨(dú)抽出來放在一個(gè) Entity 模塊下;還一種是將這些微服務(wù)模塊之間的交互傳輸對象定義在 Common 模塊中,作為 DO 或 TO 來進(jìn)行微服務(wù)之間的數(shù)據(jù)傳輸。
2.8. AO(Application Object)
AO 對象全稱為 Application Object(應(yīng)用對象),在 Web 層與 Service 層之間抽象的復(fù)用對象模型,極為貼近展示層,復(fù)用度不高。舉一個(gè)很簡單的例子:控制層(Controller) 在業(yè)務(wù)邏輯層(Service)查詢一條或多條數(shù)據(jù),這個(gè)數(shù)據(jù)的傳輸過程的運(yùn)載就是 AO 完成。在正常的業(yè)務(wù)邏輯中一般都有很多種類型的數(shù)據(jù),例如 整形、字符型、集合、類 等,我們把它統(tǒng)稱為 AO。
2.9. DAO(Data Access Object)
DAO 對象全稱為 Data Access Object(數(shù)據(jù)訪問對象),是主要封裝對數(shù)據(jù)庫的訪問。通過它可以把 POJO 持久化為 PO,用 PO 組裝出 VO 和 DTO。DAO 一般在持久層,完全封裝數(shù)據(jù)庫操作,對外暴露的方法的使得上層不需要關(guān)注數(shù)據(jù)庫的相關(guān)信息,只需要插入、刪除、更新、查詢即可。
例如 UserDao 封裝的就是對 user 表的增刪改查操作:
三. 區(qū)別和應(yīng)用
3.1. VO 與 DTO 的區(qū)別
大家可能會(huì)有個(gè)疑問:既然 DTO 是展示層與服務(wù)層之間傳遞數(shù)據(jù)的對象,為什么還需要一個(gè)VO 呢?對于絕大部分的應(yīng)用場景來說,DTO 和 VO 的屬性值基本是一致的,而且他們通常都是POJO,因此沒必要多此一舉,但不要忘記這是實(shí)現(xiàn)層面的思維,對于設(shè)計(jì)層面來說,概念上還是應(yīng)該存在 VO 和 DTO,因?yàn)閮烧哂兄举|(zhì)的區(qū)別。
DTO 代表服務(wù)層需要接收的數(shù)據(jù)和返回的數(shù)據(jù),而 VO 代表展示層需要顯示的數(shù)據(jù)。用一個(gè)例子來說明可能會(huì)比較容易理解:例如服務(wù)層有一個(gè) getUser 的方法返回一個(gè)系統(tǒng)用戶,其中有一個(gè)屬性是 gender(性別),對于服務(wù)層來說,它只從語義上定義:1-男性,2-女性,0-未指定,而對于展示層來說,它可能需要用“帥哥”代表男性,用“美女”代表女性,用“秘密”代表未指定。說到這里,可能你還會(huì)反駁,在服務(wù)層直接就返回“帥哥美女”不就行了嗎?對于大部分應(yīng)用來說,這不是問題,但設(shè)想一下,如果需求允許客戶可以定制風(fēng)格,而不同風(fēng)格對于“性別”的表現(xiàn)方式不一樣,又或者這個(gè)服務(wù)同時(shí)供多個(gè)客戶端使用(不同門戶),而不同的客戶端對于表現(xiàn)層的要求有所不同,那么,問題就來了。
再者,回到設(shè)計(jì)層面上分析,從職責(zé)單一原則來看,服務(wù)層只負(fù)責(zé)業(yè)務(wù),與具體的表現(xiàn)形式無關(guān),因此,它返回的 DTO,不應(yīng)該出現(xiàn)與表現(xiàn)形式的耦合。理論歸理論,這到底還是分析設(shè)計(jì)層面的思維,是否在實(shí)現(xiàn)層面必須這樣做呢?一刀切的做法往往會(huì)得不償失,下面我馬上會(huì)分析應(yīng)用中如何做出正確的選擇。
3.2. VO 與 DTO 的應(yīng)用
上面只是用了一個(gè)簡單的例子來說明 VO 與 DTO 在概念上的區(qū)別,本節(jié)將會(huì)告訴你如何在應(yīng)用中做出正確的選擇。在以下場景中,我們可以考慮把 VO 與 DTO 二合為一(注意,是實(shí)現(xiàn)層面):
- 需求非常清晰穩(wěn)定,而且客戶端很明確只有一個(gè)的時(shí)候,沒有必要把 VO 和 DTO 區(qū)分開來,這時(shí)候 VO 可以退隱,用一個(gè) DTO 即可,為什么是 VO 退隱而不是 DTO?回到設(shè)計(jì)層面,服務(wù)層的職責(zé)依然不應(yīng)該與展示層耦合,所以,對于前面的例子,你很容易理解,DTO 對于“性別”來說,依然不能用“帥哥美女”,這個(gè)轉(zhuǎn)換應(yīng)該依賴于頁面的腳本(如 JavaScript)或其他機(jī)制(JSTL、EL、CSS);
- 即使客戶端可以進(jìn)行定制,或者存在多個(gè)不同的客戶端,如果客戶端能夠用某種技術(shù)(腳本或其他機(jī)制)實(shí)現(xiàn)轉(zhuǎn)換,同樣可以讓 VO 退隱。
以下場景需要優(yōu)先考慮 VO、DTO 并存:
- 上述場景的反面場景;
- 因?yàn)槟撤N技術(shù)原因,比如某個(gè)框架(如 Flex)提供自動(dòng)把 POJO 轉(zhuǎn)換為 UI 中某些 Field 時(shí),可以考慮在實(shí)現(xiàn)層面定義出 VO,這個(gè)權(quán)衡完全取決于使用框架的自動(dòng)轉(zhuǎn)換能力帶來的開發(fā)和維護(hù)效率提升,與設(shè)計(jì)多一個(gè) VO 所多做的事情帶來的開發(fā)和維護(hù)效率的下降之間的比對。
- 如果頁面出現(xiàn)一個(gè)“大視圖”,而組成這個(gè)大視圖的所有數(shù)據(jù)需要調(diào)用多個(gè)服務(wù),返回多個(gè)DTO 來組裝(當(dāng)然,這同樣可以通過服務(wù)層提供一次性返回一個(gè)大視圖的 DTO 來取代,但在服務(wù)層提供一個(gè)這樣的方法是否合適,需要在設(shè)計(jì)層面進(jìn)行權(quán)衡)。
3.3. DTO 與 DO 的區(qū)別
首先是概念上的區(qū)別,DTO 是展示層和服務(wù)層之間的數(shù)據(jù)傳輸對象(可以認(rèn)為是兩者之間的協(xié)議),而 DO 是對現(xiàn)實(shí)世界各種業(yè)務(wù)角色的抽象,這就引出了兩者在數(shù)據(jù)上的區(qū)別,例如 UserInfo和 User,對于一個(gè) getUser 方法來說,本質(zhì)上它永遠(yuǎn)不應(yīng)該返回用戶的密碼,因此 UserInfo 至少比 User 少一個(gè) password 的數(shù)據(jù)。而在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)中,DO 不是簡單的 POJO,它具有領(lǐng)域業(yè)務(wù)邏輯。
3.4. DTO 與 DO 的應(yīng)用
從上一節(jié)的例子中,細(xì)心的讀者可能會(huì)發(fā)現(xiàn)問題:既然 getUser 方法返回的 UserInfo 不應(yīng)該包含 password,那么就不應(yīng)該存在 password 這個(gè)屬性定義,但如果同時(shí)有一個(gè) createUser 的方法,傳入的 UserInfo 需要包含用戶的 password,怎么辦?在設(shè)計(jì)層面,展示層向服務(wù)層傳遞的DTO 與服務(wù)層返回給展示層的 DTO 在概念上是不同的,但在實(shí)現(xiàn)層面,我們通常很少會(huì)這樣做(定義兩個(gè) UserInfo,甚至更多),因?yàn)檫@樣做并不見得很明智,我們完全可以設(shè)計(jì)一個(gè)完全兼容的 DTO,在服務(wù)層接收數(shù)據(jù)的時(shí)候,不該有展示層設(shè)置的屬性(如訂單的總價(jià)應(yīng)該由其單價(jià)、數(shù)量、折扣等決定),無論展示層是否設(shè)置,服務(wù)層都一概忽略,而在服務(wù)層返回?cái)?shù)據(jù)時(shí),不該返回的數(shù)據(jù)(如用戶密碼),就不設(shè)置對應(yīng)的屬性。
對于 DO 來說,還有一點(diǎn)需要說明:為什么不在服務(wù)層中直接返回 DO 呢?這樣可以省去 DTO 的編碼和轉(zhuǎn)換工作,原因如下:
- 兩者在本質(zhì)上的區(qū)別可能導(dǎo)致彼此并不一一對應(yīng),一個(gè) DTO 可能對應(yīng)多個(gè) DO,反之亦然,甚至兩者存在多對多的關(guān)系。
- DO 具有一些不應(yīng)該讓展示層知道的數(shù)據(jù)。
- DO 具有業(yè)務(wù)方法,如果直接把 DO 傳遞給展示層,展示層的代碼就可以繞過服務(wù)層直接調(diào)用它不應(yīng)該訪問的操作,對于基于 AOP 攔截服務(wù)層來進(jìn)行訪問控制的機(jī)制來說,這問題尤為突出,而在展示層調(diào)用 DO 的業(yè)務(wù)方法也會(huì)因?yàn)槭聞?wù)的問題,讓事務(wù)難以控制。
- 對于某些 ORM 框架(如 Hibernate)來說,通常會(huì)使用“延遲加載”技術(shù),如果直接把 DO 暴露給展示層,對于大部分情況,展示層不在事務(wù)范圍之內(nèi)(Open session in view 在大部分情況下不是一種值得推崇的設(shè)計(jì)),如果其嘗試在 Session 關(guān)閉的情況下獲取一個(gè)未加載的關(guān)聯(lián)對象,會(huì)出現(xiàn)運(yùn)行時(shí)異常(對于 Hibernate 來說,就是 LazyInitiliaztionException)。
- 從設(shè)計(jì)層面來說,展示層依賴于服務(wù)層,服務(wù)層依賴于領(lǐng)域?qū)樱绻?DO 暴露出去,就會(huì)導(dǎo)致展示層直接依賴于領(lǐng)域?qū)?,這雖然依然是單向依賴,但這種跨層依賴會(huì)導(dǎo)致不必要的耦合。
對于 DTO 來說,也有一點(diǎn)必須進(jìn)行說明,就是 DTO 應(yīng)該是一個(gè)“扁平的二維對象”,舉個(gè)例子來說:如果 User 會(huì)關(guān)聯(lián)若干個(gè)其他實(shí)體(例如 Address、Account、Region 等),那么 getUser() 返回的 UserInfo,是否就需要把其關(guān)聯(lián)的對象的 DTO 都一并返回呢?如果這樣的話,必然導(dǎo)致數(shù)據(jù)傳輸量的大增,對于分布式應(yīng)用來說,由于涉及數(shù)據(jù)在網(wǎng)絡(luò)上的傳輸、序列化和反序列化,這種設(shè)計(jì)更不可接受。如果 getUser 除了要返回 User 的基本信息外,還需要返回一個(gè) AccountId、AccountName、RegionId、RegionName,那么,請把這些屬性定義到 UserInfo 中,把一個(gè)“立體”的對象樹“壓扁”成一個(gè)“扁平的二維對象”,筆者目前參與的項(xiàng)目是一個(gè)分布式系統(tǒng),該系統(tǒng)不管三七二十一,把一個(gè)對象的所有關(guān)聯(lián)對象都轉(zhuǎn)換為相同結(jié)構(gòu)的 DTO 對象樹并返回,導(dǎo)致性能非常的慢。
3.5. DO 與 PO 的區(qū)別
DO 和 PO 在絕大部分情況下是一一對應(yīng)的,PO 是只含有 get/set 方法的 POJO,但某些場景還是能反映出兩者在概念上存在本質(zhì)的區(qū)別:
- DO 在某些場景下不需要進(jìn)行顯式的持久化,例如利用策略模式設(shè)計(jì)的商品折扣策略,會(huì)衍生出折扣策略的接口和不同折扣策略實(shí)現(xiàn)類,這些折扣策略實(shí)現(xiàn)類可以算是 DO,但它們只駐留在靜態(tài)內(nèi)存,不需要持久化到持久層,因此,這類 DO 是不存在對應(yīng)的 PO 的。
- 同樣的道理,某些場景下,PO 也沒有對應(yīng)的 DO,例如老師 Teacher 和學(xué)生 Student 存在多對多的關(guān)系,在關(guān)系數(shù)據(jù)庫中,這種關(guān)系需要表現(xiàn)為一個(gè)中間表,也就對應(yīng)有一個(gè)TeacherAndStudentPO 的 PO,但這個(gè) PO 在業(yè)務(wù)領(lǐng)域沒有任何現(xiàn)實(shí)的意義,它完全不能與任何 DO 對應(yīng)上。這里要特別聲明,并不是所有多對多關(guān)系都沒有業(yè)務(wù)含義,這跟具體業(yè)務(wù)場景有關(guān),例如:兩個(gè) PO 之間的關(guān)系會(huì)影響具體業(yè)務(wù),并且這種關(guān)系存在多種類型,那么這種多對多關(guān)系也應(yīng)該表現(xiàn)為一個(gè) DO,又如:“角色”與“資源”之間存在多對多關(guān)系,而這種關(guān)系很明顯會(huì)表現(xiàn)為一個(gè) DO——“權(quán)限”。
- 某些情況下,為了某種持久化策略或者性能的考慮,一個(gè) PO 可能對應(yīng)多個(gè) DO,反之亦然。例如客戶 Customer 有其聯(lián)系信息 Contacts,這里是兩個(gè)一對一關(guān)系的 DO,但可能出于性能的考慮(極端情況,權(quán)作舉例),為了減少數(shù)據(jù)庫的連接查詢操作,把 Customer 和Contacts 兩個(gè) DO 數(shù)據(jù)合并到一張數(shù)據(jù)表中。反過來,如果一本圖書 Book,有一個(gè)屬性是封面 Cover,但該屬性是一副圖片的二進(jìn)制數(shù)據(jù),而某些查詢操作不希望把 Cover 一并加載,從而減輕磁盤 IO 開銷,同時(shí)假設(shè) ORM 框架不支持屬性級別的延遲加載,那么就需要考慮把 Cover 獨(dú)立到一張數(shù)據(jù)表中去,這樣就形成一個(gè) DO 對應(yīng)一個(gè) PO 的情況。
- PO 的某些屬性值對于 DO 沒有任何意義,這些屬性值可能是為了解決某些持久化策略而存在的數(shù)據(jù),例如為了實(shí)現(xiàn)“樂觀鎖”,PO 存在一個(gè) version 的屬性,這個(gè) version 對于 DO 來說是沒有任何業(yè)務(wù)意義的,它不應(yīng)該在 DO 中存在。同理,DO 中也可能存在不需要持久化的屬性。
3.6. DO 與 PO 的應(yīng)用
由于 ORM 框架的功能非常強(qiáng)大而大行其道,而且 JavaEE 也推出了 JPA 規(guī)范,現(xiàn)在的業(yè)務(wù)應(yīng)用開發(fā),基本上不需要區(qū)分 DO 與 PO,PO 完全可以通過 JPA、Hibernate Annotations/hbm隱藏在 DO 之中。雖然如此,但有些問題我們還必須注意:
- 對于 DO 中不需要持久化的屬性,需要通過 ORM 顯式的聲明,如:在 JPA 中,可以利用@Transient 聲明。
- 對于 PO 中為了某種持久化策略而存在的屬性,例如 version,由于 DO、PO 合并了,必須在 DO 中聲明,但由于這個(gè)屬性對 DO 是沒有任何業(yè)務(wù)意義的,需要讓該屬性對外隱藏起來,最常見的做法是把該屬性的 get/set 方法私有化,甚至不提供 get/set 方法,但對于Hibernate 來說,這需要特別注意,由于 Hibernate 從數(shù)據(jù)庫讀取數(shù)據(jù)轉(zhuǎn)換為 DO 時(shí),是利用反射機(jī)制先調(diào)用 DO 的空參數(shù)構(gòu)造函數(shù)構(gòu)造 DO 實(shí)例,然后再利用 JavaBean 的規(guī)范反射出set 方法來為每個(gè)屬性設(shè)值,如果不顯式聲明 set 方法,或把 set 方法設(shè)置為 private,都會(huì)導(dǎo)致 Hibernate 無法初始化 DO,從而出現(xiàn)運(yùn)行時(shí)異常,可行的做法是把屬性的 set 方法設(shè)置為 protected。
- 對于一個(gè) DO 對應(yīng)多個(gè) PO,或者一個(gè) PO 對應(yīng)多個(gè) DO 的場景,以及屬性級別的延遲加載,Hibernate 都提供了很好的支持,請參考 Hibnate 的相關(guān)資料。
四. 實(shí)例講解
有一個(gè)博客系統(tǒng),數(shù)據(jù)庫中存儲(chǔ)了很多篇博客。我們會(huì)做如下設(shè)計(jì):
- 數(shù)據(jù)庫表:表中的博客包括編號、博客標(biāo)題、博客內(nèi)容、博客標(biāo)簽、博客分類、博客狀態(tài)、創(chuàng)建時(shí)間、修改時(shí)間等。
- PO:包括編號、博客標(biāo)題、博客內(nèi)容、博客標(biāo)簽、博客分類、博客狀態(tài)、創(chuàng)建時(shí)間、修改時(shí)間等。(與數(shù)據(jù)庫表中的字段一樣)。
- VO:在客戶端瀏覽器展示的頁面數(shù)據(jù),博客標(biāo)題、博客內(nèi)容、博客標(biāo)簽、博客分類、創(chuàng)建時(shí)間、上一篇博客 URL、下一篇博客 URL。
- DTO:在服務(wù)端數(shù)據(jù)傳輸?shù)膶ο螅幪?、博客?biāo)題、博客內(nèi)容、博客標(biāo)簽、博客分類、創(chuàng)建時(shí)間、上一篇博客編號、下一篇博客編號。
- DAO:數(shù)據(jù)庫增刪改查的方法,例如新增博客、刪除博客、查詢所有博客、更新博客。
- BO:基本業(yè)務(wù)操作,如管理分類、管理標(biāo)簽、修改博客狀態(tài)等,是我們常說的 Service 層操作。
- 用戶發(fā)出請求(可能是填寫表單),表單的數(shù)據(jù)在展示層被匹配為 VO。
- 展示層把 VO 轉(zhuǎn)換為服務(wù)層對應(yīng)方法所要求的 DTO,傳送給服務(wù)層。
- 服務(wù)層首先根據(jù) DTO 的數(shù)據(jù)構(gòu)建或重建一個(gè) DO,調(diào)用 DO 的業(yè)務(wù)方法完成具體業(yè)務(wù)。
- 服務(wù)層把 DO 轉(zhuǎn)換為持久層對應(yīng)的 PO(可以使用 ORM 工具,也可以不用),調(diào)用持久層的持久化方法,把 PO 傳遞給它,完成持久化操作。
- 對于一個(gè)逆向操作,如讀取數(shù)據(jù),也是用類似的方式轉(zhuǎn)換和傳遞。
五. 總結(jié)
到目前為止,相信大家都已經(jīng)比較清晰的了解了 VO、DTO、DO、PO、BO 等的概念、區(qū)別和實(shí)際應(yīng)用了。通過上面的詳細(xì)分析,我們還可以總結(jié)出一個(gè)原則:分析設(shè)計(jì)層面和實(shí)現(xiàn)層面完全是兩個(gè)獨(dú)立的層面,即使實(shí)現(xiàn)層面通過某種技術(shù)手段可以把兩個(gè)完全獨(dú)立的概念合二為一,在分析設(shè)計(jì)層面,我們?nèi)匀唬ㄖ辽僭陬^腦中)需要把概念上獨(dú)立的東西清晰的區(qū)分開來,這個(gè)原則對于做好分析設(shè)計(jì)非常重要(工具越先進(jìn),往往會(huì)讓我們越麻木)。
到此這篇關(guān)于Java中POJO、VO、DO、DTO、PO、BO、AO、DAO的概念和區(qū)別以及如何應(yīng)用的文章就介紹到這了,更多相關(guān)POJO、VO、DO、DTO、PO、BO、AO、DAO應(yīng)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring整合Mybatis 掃描注解創(chuàng)建Bean報(bào)錯(cuò)的解決方案
這篇文章主要介紹了Spring 整合Mybatis 掃描注解創(chuàng)建Bean報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10淺談MyBatis-Plus學(xué)習(xí)之Oracle的主鍵Sequence設(shè)置的方法
這篇文章主要介紹了淺談MyBatis-Plus學(xué)習(xí)之Oracle的主鍵Sequence設(shè)置的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08java打包成可執(zhí)行的jar或者exe的詳細(xì)步驟
Java程序完成以后,對于Windows操作系統(tǒng),習(xí)慣總是想雙擊某個(gè)exe文件就可以直接運(yùn)行程序,現(xiàn)我將一步一步的實(shí)現(xiàn)該過程.最終結(jié)果是:不用安裝JRE環(huán)境,不用安裝數(shù)據(jù)庫,直接雙擊一個(gè)exe文件,就可以運(yùn)行程序2014-04-04JFrame中添加和設(shè)置JPanel的方法實(shí)例解析
這篇文章主要介紹了JFrame中添加和設(shè)置JPanel的方法實(shí)例解析,具有一定借鑒價(jià)值2018-01-01