小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模式少用或者不用,可以使用相關替代技術。”