小A:“應該怎麼去應用單體模式哩?”
大B:“首先是要建立目錄,數據庫連接或Socket連接要受到一定的限製,必須保持同一時間隻能有一個連接的存在等這樣的單線程操作。使用Singleton的好處還在於可以節省內存,因為它限製了實例的個數,有利於Java垃圾回收(garbagecollection)。”
小A:“關於數據庫連接應用單體模式的問題應該怎麼去解決?”
大B:“關於把單例模式應用到數據庫connection的問題較為複雜,如果是簡單地把一個connection對象封存在單例對象中,那麼在J2EE環境中這是錯誤的。如果數據庫連接做成單例模式也就是說係統隻會存在一個數據庫連接實例,大家公用。實例不可以並發使用。因此存在排隊,單例模式管理是需要排隊的。資源有兩種,一種需要排隊,一種不需要排隊,或者需要一種複雜的排隊,譬如數據庫就是複雜的排隊問題,係統的排隊是不可避免的,應該由數據庫引擎自行解決。解決方式就是紀錄的locking,而locking不應該由Java程序解決。盡量將排隊的工作交給更低一層來做,這樣可以獲得更高的效率。但是在單用戶係統中這並不是什麼嚴重的問題,因為在某一個時刻隻有一個用戶在使用,唯一的問題就是係統可能需要幾個connection,譬如兩個、三個等,而不是一個。J2EE服務器係統中單例模式可以用來管理一個數據庫連接池(connectionpool)。單例模式可以用來保存這樣一個connectionpool,在初始化的時候創建譬如100個connection對象,然後再需要的時候提供一個,用過之後返回到pool中。如果不是用單例模式的話,這個pool存在哪裏,就是一個問題。最後可能隻好存到Application對象中。”
小A:“那關於‘全局’變量的問題又應該如何去解決?”
大B:“使用單例模式來存放‘全局’變量是違背單例模式的用意的,單例模式隻在有真正的‘單一實例’的需求時才可以使用。其次,一個設計得當的係統不應該有所謂的‘全局’變量的。這些變量應該放到他們所描述的實體所對應的類中去。將這些變量從他們所描述的實體類中抽出來,放到一個不相幹的單體類中去,使得這些變量產生錯誤的依賴關係和耦合關係。所以,如果需要的話,我們可以將一個承擔了責任的類作為一個單體類來實現,而不僅僅是為了一個‘全局’變量。”
大B:“有時使用Singleton並不能達到Singleton的目的,如有多個Singleton對象同時被不同的類裝入器裝載;在EJB這樣的分布式係統中使用也要注意這種情況,因為EJB是跨服務器,跨JVM的。總之:Singleton模式看起來簡單,使用方法也很方便,但是真正用好,是非常不容易,需要對Java的類和線程內存等概念有相當的了解。如果你的應用基於容器,那麼Singleton模式少用或者不用,可以使用相關替代技術。”
(本章完)