在過去 5 到 10 年中,開發人員對企業應用程式中的實體進行持久化的方式發生了根本性變化。早期的企業應用程式使用資料庫表和表之間的外鍵關系進行實體模組化。應用程式被看 作檢視和查詢資料庫底層模型的方式。近幾年,資料庫中的實體模組化逐漸向應用程式對象模型中的實體模組化轉變。現在大家已經意識到,資料庫僅僅是存儲對象結構 所定義的持久化資訊的一種機制。把模組化從資料庫轉移到對象模型中有許多優點,包括:
- 持久化實體與對它們執行的操作更緊密地內建
- 有助于建立松散耦合的應用程式元件
- 與關系資料庫相比,面向對象模型支援更豐富的關系
- 更加獨立于特定的資料庫平台
發生這種轉變的主要原因是出現了功能強大的對象-關系映射(ORM)系統,它們支援按照與目智語言的習慣用法一緻的方式通路持久化對象。Hibernate 和 TopLink 等工具大大簡化了把對象模型映射到關系資料庫模式的過程。
自 從這些工具出現以來,使用它們的方法也有所變化。最初,許多開發人員按照使用資料庫表的方式使用 ORM 工具。實體一對一地映射到資料庫表。對應于主鍵等字段的變量在各個實體中重複出現。因為資料庫不支援與實體相關聯的行為,領域模型最終隻具有簡單的變量以 及相關的 getter 和 setter 方法。這些實體的行為最終由服務或視圖層實作。
在許多項目中 使用 ORM 工具的經驗揭示了處理這些問題的更好方法。業務領域各不相同,是以它們的領域模型和持久化方式也可能不同,但也有相同之處。本文讨論應用于不同行業的許多 領域模型的最佳實踐。這裡提供的最佳實踐有助于産生更加一緻、可重用且可維護的領域模型。我們使用 Hibernate 示範這些最佳實踐,但是許多概念可以應用于其他 ORM 工具。
本文分為兩部分。第 1 部分讨論以下方面的一些基本概念:
- 實作領域中的通用功能
- 減少資料通路層中的代碼重複
- 按照一緻的方式處理對實體修改的審計
第 2 部分 更深入地讨論這裡介紹的一些概念,還要讨論領域模型中的性能調優。
|
從基礎開始:對象模型
定義一個支援持久化對象的對象模型的過程與定義任何對象模型相同。首先,尋找所有對象 共享的通用元素。持久化資訊中有兩個通用元素:惟一地辨別持久化對象的方法(應該能夠跨應用程式的各次執行辨別對象),以及關于對象執行個體的審計資訊。圖 1 說明如何用接口和基類定義這兩個概念:
圖 1. 通用的接口和基類
圖 1 引入了
Identifiable
和
Auditable
接口,這些接口定義的 API 用來辨別對象執行個體和設定對象執行個體的審計資訊。還引入了
BaseEntity
和
AuditableEntity
基類,可以根據是否需要對象的審計資訊,分别從這些基類派生出具體的持久化類。
通過用這些接口定義持久化對象,就可能建立出可以應用于所有具體對象類型的抽象行為。這包括 UI 層(用來辨別要執行建立、讀取、更新和删除(CRUD)操作的對象)以及服務和資料層。本文的代碼示例(在 下載下傳 中可以獲得完整的代碼包)示範如何使用這些接口幫助執行審計和減少資料通路對象(DAO)中的代碼重複。
通用的基實體
與 對象不同,資料庫表沒有繼承的概念。許多表中都有的字段(比如審計字段)必須為每個表重新定義。請牢記,可以在 Java™ 代碼中使用繼承,以避免這種重複出現在代碼中。盡管 ORM 工具早就支援這個特性,但是 Java Persistence API 注解使之大大簡化了,可以進一步減少代碼重複(參見 參考資料)。
通過使用 Java 5 注解,可以用類級注解在類源代碼中直接嵌入資料庫映射。Java Persistence API 為此定義了一套标準注解。Hibernate 和其他工具現在支援這些注解。可以通過
@MappedSuperclass
注解使用在基類中定義的映射。隻要所有資料庫表對通用字段采用相同的列類型和列名,那麼隻需在基類中編寫映射一次,就可以在所有子類中重用。清單 1 是
BaseEntity
類的一個示例:
清單 1. 用
@MappedSuperclass
定義
BaseEntity
|
清單 1 中的映射把 ID 字段映射到預設列名(
id
),并指定自動生成 ID(實作方式與資料庫相關)。
注意,即使每個表使用不同的列名,仍然可能使用這些通用基字段。請考慮一種典型情況:所有資料庫表的主鍵都是
Long
類型的,但是列名可能不一樣。通過重新定義配置設定給特定子類的一個屬性的列,仍然可以重用與
id
屬性相關的代碼。清單 2 示範如何重新定義與
id
屬性相關聯的列:
清單 2. 重新定義與
id
屬性相關聯的列
本文轉自IBM Developerworks中國
請點選此處檢視全文