VO是跟數據庫裏表的映射,一個表對應一個VOjava
DAO是用VO來訪問真實的表,對數據庫的操做都在DAO中完成程序員
BO是業務層,作邏輯處理的web
VO , PO , BO , QO, DAO ,POJO數據庫
O/R Mapping 是 Object Relational Mapping (對象關係映射)的縮寫。設計模式
通俗點講,就是將對象與關係數據庫綁定,用對象來表示關係數據。在 O/R網絡
Mapping 的世界裏,有兩個基本的也是重要的東東須要瞭解,即 VO , PO 。session
VO ,值對象 (Value Object) ,數據結構
PO ,持久對象 (Persistent Object) ,它們是由一組屬性和屬性的 get 和 set 方法組成。從結構上看,它們並無什麼不一樣的地方。但從其意義和本質上來看是徹底不一樣的。app
1. VO 是用 new 關鍵字建立,由 GC 回收的。框架
PO 則是向數據庫中添加新數據時建立,刪除數據庫中數據時削除的。而且它只能存活在一個數據庫鏈接中,斷開鏈接即被銷燬。
2. VO 是值對象,精確點講它是業務對象,是存活在業務層的,是業務邏輯使用的,它存活的目的就是爲數據提供一個生存的地方。
PO 則是有狀態的,每一個屬性表明其當前的狀態。它是物理數據的對象表示。使用它,可使咱們的程序與物理數據解耦,而且能夠簡化對象數據與物理數據之間的轉換。
3. VO 的屬性是根據當前業務的不一樣而不一樣的,也就是說,它的每個屬性都一一對應當前業務邏輯所須要的數據的名稱。
PO 的屬性是跟數據庫表的字段一一對應的。
PO 對象須要實現序列化接口。
Java的 (PO,VO,TO,BO,DAO,POJO) 解釋
PO(persistant object) 持久對象
在 o/r 映射的時候出現的概念,若是沒有 o/r 映射,沒有這個概念存在了。一般對應數據模型 ( 數據庫 ), 自己還有部分業務邏輯的處理。能夠當作是與數據庫中的表相映射的 java 對象。最簡單的 PO 就是對應數據庫中某個表中的一條記錄,多個記錄能夠用 PO 的集合。 PO 中應該不包含任何對數據庫的操做。
VO(value object) 值對象
一般用於業務層之間的數據傳遞,和 PO 同樣也是僅僅包含數據而已。但應是抽象出的業務對象 , 能夠和表對應 , 也能夠不 , 這根據業務的須要 . 我的以爲同 DTO( 數據傳輸對象 ), 在 web上傳遞。
TO(Transfer Object) ,數據傳輸對象
在應用程序不一樣 tie( 關係 ) 之間傳輸的對象
BO(business object) 業務對象
從業務模型的角度看 , 見 UML 元件領域模型中的領域對象。封裝業務邏輯的 java 對象 , 經過調用 DAO 方法 , 結合 PO,VO 進行業務操做。
business object: 業務對象
主要做用是把業務邏輯封裝爲一個對象。這個對象能夠包括一個或多個其它的對象。
好比一個簡歷,有教育經歷、工做經歷、社會關係等等。
咱們能夠把教育經歷對應一個 PO ,工做經歷對應一個 PO ,社會關係對應一個 PO 。
創建一個對應簡歷的 BO 對象處理簡歷,每一個 BO 包含這些 PO 。
這樣處理業務邏輯時,咱們就能夠針對 BO 去處理。
QO :查詢對象
POJO(plain ordinary Java object) 簡單無規則 java 對象
純的傳統意義的 java 對象。就是說在一些 Object/Relation
Mapping 工具中,可以作到維護數據庫表記錄的 persisent
object 徹底是一個符合 java Bean 規範的純 Java 對象,沒有增長別的屬性和方法。個人理解就是最基本的 Java Bean ,只有屬性字段及 setter 和 getter 方法!。
DAO(data access object) 數據訪問對象
是一個 sun 的一個標準 j2ee 設計模式, 這個模式中有個接口就是 DAO ,它負持久層的操做。爲業務層提供接口。此對象用於訪問數據庫。一般和 PO 結合使用, DAO 中包含了各類數據庫的操做方法。經過它的方法 , 結合 PO 對數據庫進行相關的操做。夾在業務邏輯與數據庫資源中間。配合 VO,
提供數據庫的 CRUD 操做 ...
DTO :
Data Transfer Object 數據傳輸對象
主要用於遠程調用等須要大量傳輸對象的地方。
好比咱們一張表有 100 個字段,那麼對應的 PO 就有 100 個屬性。
可是咱們界面上只要顯示 10 個字段,
客戶端用 WEB service 來獲取數據,沒有必要把整個 PO 對象傳遞到客戶端,
這時咱們就能夠用只有這 10 個屬性的 DTO 來傳遞結果到客戶端,這樣也不會暴露服務端表結構 . 到達客戶端之後,若是用這個對象來對應界面顯示,那此時它的身份就轉爲 VO
DAO :數據訪問對象 —— 同時還有 DAO 模式
DTO :數據傳輸對象 —— 同時還有 DTO 模式
示例:
VO(View Object):視圖對象,用於展現層,它的做用是把某個指定頁面(或組件)的全部數據封裝起來。
DTO(Data Transfer Object):數據傳輸對象,這個概念來源於J2EE的設計模式,原來的目的是爲了EJB的分佈式應用提供粗粒度的數據實體,以減小分佈式調用的次數,從而提升分佈式調用的性能和下降網絡負載,但在這裏,我泛指用於展現層與服務層之間的數據傳輸對象。
DO(Domain Object):領域對象,就是從現實世界中抽象出來的有形或無形的業務實體。
PO(Persistent Object):持久化對象,它跟持久層(一般是關係型數據庫)的數據結構造成一一對應的映射關係,若是持久層是關係型數據庫,那麼,數據表中的每一個字段(或若干個)就對應PO的一個(或若干個)屬性。
VO與DTO的區別
你們可能會有個疑問(在筆者參與的項目中,不少程序員也有相同的疑惑):既然DTO是展現層與服務層之間傳遞數據的對象,爲何還須要一個VO呢?對!對於絕大部分的應用場景來講,DTO和VO的屬性值基本是一致的,並且他們一般都是POJO,所以不必畫蛇添足,但不要忘記這是實現層面的思惟,對於設計層面來講,概念上仍是應該存在VO和DTO,由於二者有着本質的區別,DTO表明服務層須要接收的數據和返回的數據,而VO表明展現層須要顯示的數據。
用一個例子來講明可能會比較容易理解:例如服務層有一個getUser的方法返回一個系統用戶,其中有一個屬性是gender(性別),對於服務層來講,它只從語義上定義:1-男性,2-女性,0-未指定,而對於展現層來講,它可能須要用「帥哥」表明男性,用「美女」表明女性,用「祕密」表明未指定。說到這裏,可能你還會反駁,在服務層直接就返回「帥哥美女」不就好了嗎?對於大部分應用來講,這不是問題,但設想一下,若是需求容許客戶能夠定製風格,而不一樣風格對於「性別」的表現方式不同,又或者這個服務同時供多個客戶端使用(不一樣門戶),而不一樣的客戶端對於表現層的要求有所不一樣,那麼,問題就來了。再者,回到設計層面上分析,從職責單一原則來看,服務層只負責業務,與具體的表現形式無關,所以,它返回的DTO,不該該出現與表現形式的耦合。
理論歸理論,這到底仍是分析設計層面的思惟,是否在實現層面必須這樣作呢?一刀切的作法每每會得不償失,下面我立刻會分析應用中如何作出正確的選擇。
VO與DTO的應用
上面只是用了一個簡單的例子來講明VO與DTO在概念上的區別,本節將會告訴你如何在應用中作出正確的選擇。
在如下才場景中,咱們能夠考慮把VO與DTO二合爲一(注意:是實現層面):
當需求很是清晰穩定,並且客戶端很明確只有一個的時候,沒有必要把VO和DTO區分開來,這時候VO能夠退隱,用一個DTO便可,爲何是VO退隱而不是DTO?回到設計層面,服務層的職責依然不該該與展現層耦合,因此,對於前面的例子,你很容易理解,DTO對於「性別」來講,依然不能用「帥哥美女」,這個轉換應該依賴於頁面的腳本(如JavaScript)或其餘機制(JSTL、EL、CSS)
即便客戶端能夠進行定製,或者存在多個不一樣的客戶端,若是客戶端可以用某種技術(腳本或其餘機制)實現轉換,一樣可讓VO退隱
如下場景須要優先考慮VO、DTO並存:
上述場景的反面場景
由於某種技術緣由,好比某個框架(如Flex)提供自動把POJO轉換爲UI中某些Field時,能夠考慮在實現層面定義出VO,這個權衡徹底取決於使用框架的自動轉換能力帶來的開發和維護效率提高與設計多一個VO所多作的事情帶來的開發和維護效率的降低之間的比對。
若是頁面出現一個「大視圖」,而組成這個大視圖的全部數據須要調用多個服務,返回多個DTO來組裝(固然,這一樣能夠經過服務層提供一次性返回一個大視圖的DTO來取代,但在服務層提供一個這樣的方法是否合適,須要在設計層面進行權衡)。
DTO與DO的區別
首先是概念上的區別,DTO是展現層和服務層之間的數據傳輸對象(能夠認爲是二者之間的協議),而DO是對現實世界各類業務角色的抽象,這就引出了二者在數據上的區別,例如UserInfo和User(對於DTO和DO的命名規則,請參見筆者前面的一篇博文),對於一個getUser方法來講,本質上它永遠不該該返回用戶的密碼,所以UserInfo至少比User少一個password的數據。而在領域驅動設計中,正如第一篇系列文章所說,DO不是簡單的POJO,它具備領域業務邏輯。
DTO與DO的應用
從上一節的例子中,細心的讀者可能會發現問題:既然getUser方法返回的UserInfo不該該包含password,那麼就不該該存在password這個屬性定義,但若是同時有一個createUser的方法,傳入的UserInfo須要包含用戶的password,怎麼辦?在設計層面,展現層向服務層傳遞的DTO與服務層返回給展現層的DTO在概念上是不一樣的,但在實現層面,咱們一般不多會這樣作(定義兩個UserInfo,甚至更多),由於這樣作並不見得很明智,咱們徹底能夠設計一個徹底兼容的DTO,在服務層接收數據的時候,不應由展現層設置的屬性(如訂單的總價應該由其單價、數量、折扣等決定),不管展現層是否設置,服務層都一律忽略,而在服務層返回數據時,不應返回的數據(如用戶密碼),就不設置對應的屬性。
對於DO來講,還有一點須要說明:爲何不在服務層中直接返回DO呢?這樣能夠省去DTO的編碼和轉換工做,緣由以下:
二者在本質上的區別可能致使彼此並不一一對應,一個DTO可能對應多個DO,反之亦然,甚至二者存在多對多的關係。
DO具備一些不該該讓展現層知道的數據
DO具備業務方法,若是直接把DO傳遞給展現層,展現層的代碼就能夠繞過服務層直接調用它不該該訪問的操做,對於基於AOP攔截服務層來進行訪問控制的機制來講,這問題尤其突出,而在展現層調用DO的業務方法也會由於事務的問題,讓事務難以控制。
對於某些ORM框架(如hibernate)來講,一般會使用「延遲加載」技術,若是直接把DO暴露給展現層,對於大部分狀況,展現層不在事務範圍以內(Open session in view在大部分狀況下不是一種值得推崇的設計),若是其嘗試在Session關閉的狀況下獲取一個未加載的關聯對象,會出現運行時異常(對於Hibernate來講,就是LazyInitiliaztionException)。
從設計層面來講,展現層依賴於服務層,服務層依賴於領域層,若是把DO暴露出去,就會致使展現層直接依賴於領域層,這雖然依然是單向依賴,但這種跨層依賴會致使沒必要要的耦合。
對於DTO來講,也有一點必須進行說明,就是DTO應該是一個「扁平的二維對象」,舉個例子來講明:若是User會關聯若干個其餘實體(例如Address、Account、Region等),那麼getUser()返回的UserInfo,是否就須要把其關聯的對象的DTO都一併返回呢?若是這樣的話,必然致使數據傳輸量的大增,對於分佈式應用來講,因爲涉及數據在網絡上的傳輸、序列化和反序列化,這種設計更不可接受。若是getUser除了要返回User的基本信息外,還須要返回一個AccountId、AccountName、RegionId、RegionName,那麼,請把這些屬性定義到UserInfo中,把一個「立體」的對象樹「壓扁」成一個「扁平的二維對象」,筆者目前參與的項目是一個分佈式系統,該系統無論三七二十一,把一個對象的全部關聯對象都轉換爲相同結構的DTO對象樹並返回,致使性能很是的慢。
DO與PO的區別
DO和PO在絕大部分狀況下是一一對應的,PO是隻含有get/set方法的POJO,但某些場景仍是能反映出二者在概念上存在本質的區別:
DO在某些場景下不須要進行顯式的持久化,例如利用策略模式設計的商品折扣策略,會衍生出折扣策略的接口和不一樣折扣策略實現類,這些折扣策略實現類能夠算是DO,但它們只駐留在靜態內存,不須要持久化到持久層,所以,這類DO是不存在對應的PO的。
一樣的道理,某些場景下,PO也沒有對應的DO,例如老師Teacher和學生Student存在多對多的關係,在關係數據庫中,這種關係須要表現爲一箇中間表,也就對應有一個TeacherAndStudentPO的PO,但這個PO在業務領域沒有任何現實的意義,它徹底不能與任何DO對應上。這裏要特別聲明,並非全部多對多關係都沒有業務含義,這跟具體業務場景有關,例如:兩個PO之間的關係會影響具體業務,而且這種關係存在多種類型,那麼這種多對多關係也應該表現爲一個DO,又如:「角色」與「資源」之間存在多對多關係,而這種關係很明顯會表現爲一個DO——「權限」。
某些狀況下,爲了某種持久化策略或者性能的考慮,一個PO可能對應多個DO,反之亦然。例如客戶Customer有其聯繫信息Contacts,這裏是兩個一對一關係的DO,但可能出於性能的考慮(極端狀況,權做舉例),爲了減小數據庫的鏈接查詢操做,把Customer和Contacts兩個DO數據合併到一張數據表中。反過來,若是一本圖書Book,有一個屬性是封面cover,但該屬性是一副圖片的二進制數據,而某些查詢操做不但願把cover一併加載,從而減輕磁盤IO開銷,同時假設ORM框架不支持屬性級別的延遲加載,那麼就須要考慮把cover獨立到一張數據表中去,這樣就造成一個DO對應對個PO的狀況。
PO的某些屬性值對於DO沒有任何意義,這些屬性值多是爲了解決某些持久化策略而存在的數據,例如爲了實現「樂觀鎖」,PO存在一個version的屬性,這個version對於DO來講是沒有任何業務意義的,它不該該在DO中存在。同理,DO中也可能存在不須要持久化的屬性。
DO與PO的應用
因爲ORM框架的功能很是強大而大行其道,並且JavaEE也推出了JPA規範,如今的業務應用開發,基本上不須要區分DO與PO,PO徹底能夠經過JPA,Hibernate Annotations/hbm隱藏在DO之中。雖然如此,但有些問題咱們還必須注意:
對於DO中不須要持久化的屬性,須要經過ORM顯式的聲明,如:在JPA中,能夠利用@Transient聲明。
對於PO中爲了某種持久化策略而存在的屬性,例如version,因爲DO、PO合併了,必須在DO中聲明,但因爲這個屬性對DO是沒有任何業務意義的,須要讓該屬性對外隱藏起來,最多見的作法是把該屬性的get/set方法私有化,甚至不提供get/set方法,但對於Hibernate來講,這須要特別注意,因爲Hibernate從數據庫讀取數據轉換爲DO時,是利用反射機制先調用DO的空參數構造函數構造DO實例,而後再利用JavaBean的規範反射出set方法來爲每一個屬性設值,若是不顯式聲明set方法,或把set方法設置爲private,都會致使Hibernate沒法初始化DO,從而出現運行時異常,可行的作法是把屬性的set方法設置爲protected。
對於一個DO對應多個PO,或者一個PO對應多個DO的場景,以及屬性級別的延遲加載,Hibernate都提供了很好的支持,請參考Hibnate的相關資料。
O/R Mapper 對象 / 關係 映射
定義好全部的 mapping 以後,這個 O/R
Mapper 能夠幫咱們作不少的工做。經過這些 mappings, 這個 O/R
Mapper 能夠生成全部的關於對象保存,刪除,讀取的 SQL 語句,咱們再也不須要寫那麼多行的 DAL 代碼了。
實體 Model( 實體模式 )
DAL( 數據訪問層 )
IDAL( 接口層 )
DALFactory( 類工廠 )
BLL( 業務邏輯層 )
BOF Business Object Framework 業務對象框架
SOA Service Orient Architecture 面向服務的設計
EMF Eclipse Model Framework
Eclipse 建模框架