原文鏈接:http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx
雖然這篇文章不是我寫的,但我完全同意文章中的觀點。Brian Button可能是我所知道的最有才的人之一。我相信他會喜歡你們的反饋的。
1、單例模式經常被用來為某些服務提供一個全局訪問點
沒錯,是可以這麼做,但代價是什麼呢?眾所周知,單例模式為你的應用程序中的某些服務提供全局訪問點,這樣你就不必到處傳遞一個該服務的引用。這和一個全局變量有什麼區別呢?(記住,全局變量是不好的,不是嗎?)最終會發生的事情便是你設計中的依賴關系是隱藏在代碼中的,這種依賴關系不能夠通過檢查你的類和方法的接口所見。你必須檢查代碼以便准確地知道你的類中都用了哪些其他對象。這可能會是不清楚的(譯者注:不知道是不是這麼翻譯,原文:This is less clear than it could be)。沖動地創建一個全局性的東西來避免把其傳來傳去是你設計中的異味,這不是全局變量或者單例的功能。如果你更仔細地檢查你的設計,你幾乎總是能想到一種不必把“流浪數據”四處傳遞到每個對象和方法的更好的設計。
2、單例模式允許你限制你所創建的對象的數量
這也是對的,但是現在你混合了兩個不同的職責到同一個類中了,這是違反了單一職責原則的。一個類不應該關心它是否是一個單例,它應該僅僅關心它的業務職責。如果你想限制某些類的實例化能力,創建一個封裝了創建並且如你所願的那樣限制創建能力的工廠或者對象生成器,這樣創建職責便從業務實體職責中劃分出來了。
3、單例模式促進了類之間的緊耦合
使代碼是可測試的一個基本屬性便是它和其周圍環境是松耦合的。這個屬性允許你在測試過程中為了實現特定的測試目標(想想模擬對象)替換備用的合作者。單例模式把單例對象的確切類型緊耦合在一起,喪失了使用多態來替換的機會。一個更好的選擇,如上面第一點所討論到的,便是改變你的設計以便允許你傳遞對象的引用到你的類和方法中,這樣可以減輕上述的耦合問題。
4、單例模式在程序的持續過程中一直保存著上一次的狀態
持久狀態是單元測試的敵人。讓單元測試有效的事情之一便是每個測試必須獨立於其他所有測試。如果不是這樣,那麼測試運行的順序會影響到測試的結果。這可能會導致測試在不應該失敗的地方失敗,甚至更壞的事情是僅僅因為測試的運行順序導致測試通過。這可能會隱藏住bugs並且是邪惡的。防止狀態從一個測試攜帶到另一個測試的一個很好辦法便是避免使用靜態變量。單例模式,就其本質而言,依賴於在一個靜態變量中保存著一個實例。這是測試依賴的一個挑戰,可以通過傳遞對象的引用到你的類和方法中來避免。
希望這篇文章或多或少地闡釋了我對於單例模式觀點。我有一個從google或者其他地方找到的一個小鏈接集,包括Jim Hyslop和Herb Sutter,他們同樣分享了這些觀點。如果你喜歡他們那麼讓我知道吧。
更多文章請關注我的個人博客:http://www.nomoneynowife.com