Hibernate 模板設計模式
1. 前言
本節課和大家一起使用模板設計模式重構 Hibernate 操作流程,通過本節課程內容,你將了解到:
- 如何運用模板設計模式重構 Hibernate 操作流程;
- 持久化對象與序列化接口;
2. 模板設計模式
學習 Hibernate 的過程,如同訓練場上練兵。終有一天,你要奔赴真正的戰場(真實項目)。
所以,隨時隨地,要審視代碼、重構代碼。
2.1 什么是模板化操作
OOP 中有一個編碼原則 : 寫僅寫一次 。翻譯過來就是,不要重復,要重用。
如何簡化測試實例:
答案是:使用模板設計模式進一步封裝 Hibernate 的操作。
在真實項目中,Hibernate 僅僅只是完成項目中的一部分工作,需要和其它,如 Spring 等框架聯合工作,一起承擔整體項目的開發。
Spring 框架中就提供的有 Hibernate 模板對象。
模板設計模式的應用場景:
一個常規的、頻繁的操作代碼中,大部分代碼不需要變動,只有小部分代碼需要根據需求變動。這種場景下的代碼,可認為是模板化操作流程代碼,可使用模板設計模式進行重構。
JDBC 就是一個標準化的模板化操作過程。可以說,Hibernate 是一個操作 JDBC 的模板化框架。
Hiberante 雖然高度簡化 JDBC 操作流程,但使用期間,還是需要按部就班的:
- 創建配置對象;
- 創建會話工廠;
- 創建會話對象;
- 創建事務對象;
- 終于輪到完成需求;
- 嘿,記得…… 關閉會話對象!謝謝提醒,差點忘記了。
好無聊呀,重復的事情,總是讓人很容易麻木。內心掙扎時刻,便是想辦法應對時刻。
本文中把不需要改變的代碼稱為模板代碼。
好了,現在開始,一起使用模板設計模式繼續簡化 Hibernate 的操作流程。這種感覺就像風一樣自由。
2.2 模板化流程
先畫一個圖,簡要說一下模板化的基本思路:
一個模板對象中有 2 種類型代碼:
- 模板代碼: 公共的代碼,不需要變更的代碼;
- 通知代碼: 告訴調用者,此處應該是你來做了。一般采用接口的方式進行通知。
可以得出一個結論,對于一件事情,原來完全是靠調用者獨立完成,現在分攤到了兩個對象上,模板對象完成公共部分代碼,調用者完成屬于自己需求的代碼。
有了上面的理解基礎,便知,一個完整的模板調用過程,會涉及到 3 個角色:
- 調用者角色: 使用者;
- 模板角色: 封裝公共代碼,簡化使用者的操作;
- 接口角色: 調用者和模板角色之間的連接通道,互相通信;
下面進行具體實例編寫:
- 構建一個 HibernateTemplate 類,模板角色:
public class HibernateTemplate<T extends Serializable > {
private SessionFactory sessionFactory;
public HibernateTemplate() {
// 模板代碼
Configuration configuration = new Configuration().configure();
// 模板代碼
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties())
.buildServiceRegistry();
// 模板代碼
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}
public T template(Notify<T> notify) {
// 模板代碼
Session session = sessionFactory.openSession();
// 模板代碼
Transaction transaction = null;
try {
// 模板代碼
transaction = session.beginTransaction();
// 通知代碼
T result = notify.action(session);
transaction.commit();
return result;
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
return null;
}
}
- 接口角色:
public interface Notify<T extends Serializable> {
T action(Session session);
}
- 調用者角色:此處為測試實例:
HibernateTemplate<Student> hibernateTemplate=new HibernateTemplate<Student>();
Student stu= hibernateTemplate.template(new Notify<Student>() {
@Override
public Student action(Session session) {
return (Student)session.get(Student.class, new Integer(1));
}
});
System.out.println(stu.getStuName());
- 控制臺輸出結果不再貼出。不要懷疑,結果一定是你所期望的。
模板對象中的接口非常重要:
- 通知作用,并等待調用者的響應。接口中的方法也可稱為回調方法;
- 模板對象通過接口的方式暴露出 Session 給調用者,調用者不需要關心 Session 是怎么來的,安心使用便是。
模板對象中可以進一步封裝 Session 對象中的相關方法,如:
public T get(Class<?> clz, Serializable ser) {
// 模板代碼
Session session = sessionFactory.openSession();
// 模板代碼
Transaction transaction = null;
try {
// 模板代碼
transaction = session.beginTransaction();
T result = (T) session.get(clz, ser);
transaction.commit();
return result;
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
return null;
}
測試實例:
HibernateTemplate<Student> hibernateTemplate=new HibernateTemplate<Student>();
Student stu= hibernateTemplate.get(Student.class, new Integer(1));
System.out.println(stu.getStuName());
是不是開心的不要不要的,除了在模板類中需要寫一次 Hibernate 常規流程外,具體操作時,直接上模板對象。
對于任何知識不要理所當然地接受,要善于發現代碼中冗余的地方,逐步形成代碼意識,隨時改進代碼。
3. 序列化
不知道大家發現沒有,模板對象的泛型聲明:
public class HibernateTemplate<T extends Serializable>{}
前面課程使用 Session 對象中的方法時,Serializable 接口時不時的就蹦出來,為什么 Hibernate 要求持久化類實現 Serializable 接口?
為什么使用 Sesssion 的方法,某些參數也需要一個實現 Serializable 接口的對象。
public Object load(Class theClass, Serializable id);
public Object get(Class clazz, Serializable id);
原因很簡單,如果你真正了解什么是序列化。
所謂序列化,通俗理解:
以二進制的形式存儲對象中的數據,這個過程就叫序列化。相反的,把存儲的二進制數據恢復成對象數據,這個過程是反序列化。
序列化的目的,就是要以對象為單元進行數據存儲,存儲并不限于本地磁盤,可以是網絡等環境。
序列化屏蔽底層繁瑣的編碼、解碼過程,完全以一種面向對象的理念進行數據存儲。提高開發效率。
Hiberante 為什么要求持久化對象實現序列化?
- 緩存數據: 如先把一個查詢出來的對象數據以序列化的方式存儲到內存或磁盤中,需要時再讀出來,再持久化到數據庫中;
- 網絡數據傳輸: 需要把持久化數據從一個系統傳到另一個系統時,可能兩個系統是基于兩個平臺,在異構化的系統中通過二進制進行數據傳遞,可打破這種壁壘。
不管怎樣,讓對象具有序列化能力,有點像《終結者》中的液態機器人,隨時把自己液態化,來去自由。適應不同的需求場景。
4. 小結
本節課也要到說再見的時候,留一個問題給大家:如果在持久化類中重寫 equals 方法,為什么也要求重寫 hashCode 方法。
答案其實就在于你對這兩個方法的理解了。
好了!本節課,和大家一起使用模板設計模式封裝了 Hibernate 的操作代碼。讓 Hibernate 的使用過程變得更簡單,更是為了適應真實項目需求。
本節課程也和大家一起聊到了持久化對象為什么要實現序列化接口。