# 牛年自強計畫 Week 7 - SpringBoot - POJO 介紹
## 【前言】
Java 開發人員應該常會接觸到所謂的 PO、VO、BO、DTO、DAO 等等物件名稱。
他是一個實際的類或套件嗎?
還是理念的實現?
還是約定俗成的類群名稱?
是 JavaBean?
是 Entity?
如果你有不了解、不清楚、覺得有誤區的話,那接下來的內容將幫助你理解何謂 POJO,以及它們在 Java 中的角色。
## 【POJO】

全名 **Plain Old Java Object**,意為 **簡單 Java 物件** (絕對不是什麼老 Java 物件...),是 **Martin Fowler**、**Rebecca Parsons** 和**Josh MacKenzie** 在 2000 年時提出。
因為 POJO 並沒有嚴謹規範的定義,因此 Kai 整理了 POJO 的 **核心精神** 列在下方,幫助大家更容易理解:
- **簡單、普通的 Java 物件**
- **可包含業務處理邏輯或資料持久化邏輯**
- **不可繼承或實現他類 (不包含實現序列化)**
- **不受限制的類,包含上述為不可繼承、不可實現、不可作 Annotation 處理 (然而現在越來越多 @Annotation 風格的 POJO 導致這部分已不符合技術潮流而拿掉)**
很多人會把 **POJO** 跟 **JavaBean** 搞混,來看看 **JavaBean** 的 **約定**:
- **須有一個 public 的無參數建構子**
- **所有屬性設置為 private**
- **屬性需透過 setter/getter 處理,並有命名的規範**
- **可序列化**
- 能夠靈活被應用到其他類當中
可以發現 JavaBean 的約定比起 POJO 來說,在針對屬性與其方法的部分更嚴謹,因此可以把 JavaBean 視為 **遵從特定屬性處理與命名規範的POJO**
**※ 兩者最大差別為 JavaBean 不會有業務邏輯處理部分,但 POJO 可以**
而一般我們熟知的 **Entity** 則是:
- **設有配對 DB Table 的環境參數屬性或 Annotaion**
- **設有配對 DB Table 的 Key 屬性或 Annotation**
- **設有配對 Columns 的屬性與對應的 setter/getter 方法**
- **可序列化**
在這之中頻繁使用到 Annotation 的部份則已將 **Entity** 與 **POJO** 給視為兩種不同的東西。
兩者在資料處理方面有沒有相似? 非常相似,甚至可以說很多人都搞不懂兩者區別。
簡單來說,**Entity 是面向 DB 的物件**,處理的不僅有資料持久化,還包含配對 Table 的設定,而 **POJO 則面向程式**,更靠近 **JavaBean** 的定位。兩者在實務上是可以搭配使用的,並不侷限說只能採用一種。
> 理論要套用到實務面往往會遇到很多困難,Entity 和 POJO 要如何搭配使用除了要懂其理論與核心精神以外,更講究經驗法則,架構師的影響格外重大。畢竟在現實層面來說,實作比理論還重要,但理論可以讓實作更明確和清晰。
## 【分類】
POJO 可以視為一個中間對象,正如上述所言,POJO 與 JavaBean 的定位非常類似,但自由度上又比 JavaBean 高,例如: 我們常看到的 DAO 類就是一種 POJO
POJO 在不同狀況下又分為下列幾種:
| 名稱 | 全名 | 適用狀況 |
| ---- | ---- | ---- |
| **PO** | **Persistant Object** | 與資料來源直接相關的類 |
| **DTO** | **Data Transfer Object** | 與資料傳輸相關的類 |
| **VO** | **Value Object** | 資料與使用者直接相關的類 |
| **DAO** | **Data Access Object** | 封裝與 DB 連動,並轉換資料為 PO 的類 |
| **BO** | **Buesiness Object** | 負責集合 PO/VO 相關的類 |
### 【PO】
在 Entity 概念出來之前,作為與 DB Table 映射對照用的 POJO 類,其組成為對照 Columns 的屬性以及 setter/getter 方法,亦可稱其為一個純粹的 JavaBean。一個實體負責對應一筆資料。
作為一個 PO,除了上述以外,還須符合以下幾個條件:
- 不可包含任何對資料庫的操作
- 屬性與 Columns 名稱一一對應
- 必須序列化
在 ORM 中存在的 PO 亦可視作一個完全純粹的 JavaBean
#### 【PO】範例
```java=
public class table{
private String column1;
private int column2;
public void setColumn1(String column1){
this.column1 = column1;
}
public void setColumn2(int column2){
this.column2 = column2;
}
public String getColumn1(){
return this.column1;
}
public int getColumn2(){
return this.column2;
}
}
```
### 【DTO】
當資料的處理階段已從源頭取得、並且進行了調整後,進入傳輸的階段,這一個階段的資料類別會被稱為 DTO。
簡單來說,無論是從 DB 取出完整的100個欄位的資料列,或是 remote 得到的資料集合多大。
若下一個步驟是需要經過一段處理(縮減到50個欄位、增加到150個欄位、或整合資料集合之類)再轉傳出去的話,這些負責轉傳處理後資料持久化的類別就稱做 DTO。
### 【VO】
與 DTO 的前半部分相同,但後半部分為當資料的接收者為終端用戶(客戶、使用者等),這些類別稱為 VO。
通常也作為業務邏輯層的資料持久化類別,負責提供給 API 作為提供回應類別用。
> VO 與 DTO 最大的區別在於:
> - VO 通常是作為傳與前端展示給客戶、使用者查看的資料類別
> - DTO 則是後端負責跟諸多服務溝通用的資料類別
>
> 而兩者的資料來源都可能為 PO 或其他服務提供
### 【DAO】
DAO 是一開始接觸 DB 處理資料時候最常用到的類別,主要用來
1. 封裝訪問 DB 的方法並提供給業務邏輯層的類別使用
2. 將取得的資料轉換為 PO 類別做持久化處理
### 【BO】
BO 是比較特別的 POJO 類,他的概念偏向 POJO 的集合,是作為一個含括其它 PO 或 VO 使用的類別存在。
例如:一個運動員,我們可以把他的球類運動成績寫成一個 PO、田徑運動成績寫成第二個 PO、其它類推,這些 POs 總括起來可以是該名運動員的 BO,往後我們需要查閱該運動員的項目資料,只需要從這個 BO 中取出對應的 PO 即可。
## 【心得】
POJO類看半天會朦是真的,實際難完全應用於工作上,畢竟不是每一位工程師都理解清楚各個 POJO 類的意義與使用情境,所以建議使用以少量幾種即可,例如 VO DTO 這種常用的。
PO 和 DAO 因為目前 SpringBoot + ORM Entity 的模組,已經自動封裝處理的關係,應該不會需要自行寫到。
工程類的東西,講求精益求精的同時,也要看看這份精是否可以傳承下去?
首頁 [Kai 個人技術 Hackmd](/2G-RoB0QTrKzkftH2uLueA)
###### tags: `Spring Boot`