程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java模式設計之單例模式(二)

Java模式設計之單例模式(二)

編輯:關於JAVA

在什麼情況下使用單例模式

使用單例模式的條件

使用單例模式有一個很重要的必要條件:

在一個系統要求一個類只有一個實例時才應當使用單例模式。反過來說,如果一個類可以有幾個實例共存,那麼就沒有必要使用單例類。但是有經驗的讀者可能會看到很多不當地使用單例模式的例子,可見做到上面這一點並不容易,下面就是一些這樣的情況。

例子一

問:我的一個系統需要一些"全程"變量。學習了單例模式後,我發現可以使用一個單例類盛放所有的"全程"變量。請問這樣做對嗎?

答:這樣做是違背單例模式的用意的。單例模式只應當在有真正的"單一實例"的需求時才可使用。

一個設計得當的系統不應當有所謂的"全程"變量,這些變量應當放到它們所描述的實體所對應的類中去。將這些變量從它們所描述的實體類中抽出來, 放到一個不相干的單例類中去,會使得這些變量產生錯誤的依賴關系和耦合關系。

例子二

問:我的一個系統需要管理與數據庫的連接。學習了單例模式後,我發現可以使用一個單例類包裝一個Connection 對象,並在finalize()方法中關閉這個Connection 對象。這樣的話,在這個單例類的實例沒有被人引用時,這個finalize() 對象就會被調用,因此,Connection 對象就會被釋放。這多妙啊。

答:這樣做是不恰當的。除非有單一實例的需求,不然不要使用單例模式。在這裡Connection 對象可以同時有幾個實例共存,不需要是單一實例。

單例模式有很多的錯誤使用案例都與此例子相似,它們都是試圖使用單例模式管理共享資源的生命周期,這是不恰當的。

單例類的狀態

有狀態的單例類

一個單例類可以是有狀態的(stateful),一個有狀態的單例對象一般也是可變(mutable) 單例對象。

有狀態的可變的單例對象常常當做狀態庫(repositary)使用。比如一個單例對象可以持有一個int 類型的屬性,用來給一個系統提供一個數值惟一的序列號碼,作為某個販賣系統的賬單號碼。當然,一個單例類可以持有一個聚集,從而允許存儲多個狀態。

沒有狀態的單例類

另一方面,單例類也可以是沒有狀態的(stateless), 僅用做提供工具性函數的對象。既然是為了提供工具性函數,也就沒有必要創建多個實例,因此使用單例模式很合適。一個沒有狀態的單例類也就是不變(Immutable) 單例類; 關於不變模式,讀者可以參見本書的"不變(Immutable )模式"一章。

多個JVM 系統的分散式系統

EJB 容器有能力將一個EJB 的實例跨過幾個JVM 調用。由於單例對象不是EJB,因此,單例類局限於某一個JVM 中。換言之,如果EJB 在跨過JVM 後仍然需要引用同一個單例類的話,這個單例類就會在數個JVM 中被實例化,造成多個單例對象的實例出現。一個J2EE應用系統可能分布在數個JVM 中,這時候不一定需要EJB 就能造成多個單例類的實例出現在不同JVM 中的情況。

如果這個單例類是沒有狀態的,那麼就沒有問題。因為沒有狀態的對象是沒有區別的。但是如果這個單例類是有狀態的, 那麼問題就來了。舉例來說,如果一個單例對象可以持有一個int 類型的屬性,用來給一個系統提供一個數值惟一的序列號碼,作為某個販賣系統的賬單號碼的話,用戶會看到同一個號碼出現好幾次。

在任何使用了EJB、RMI 和JINI 技術的分散式系統中,應當避免使用有狀態的單例模式。

多個類加載器

同一個JVM 中會有多個類加載器,當兩個類加載器同時加載同一個類時,會出現兩個實例。在很多J2EE 服務器允許同一個服務器內有幾個Servlet 引擎時,每一個引擎都有獨立的類加載器,經有不同的類加載器加載的對象之間是絕緣的。

比如一個J2EE 系統所在的J2EE 服務器中有兩個Servlet 引擎:一個作為內網給公司的網站管理人員使用;另一個給公司的外部客戶使用。兩者共享同一個數據庫,兩個系統都需要調用同一個單例類。如果這個單例類是有狀態的單例類的話,那麼內網和外網用戶看到的單例對象的狀態就會不同。除非系統有協調機制,不然在這種情況下應當盡量避免使用有狀態的單例類。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved