2011-08-04 26 views
6

我在使用picocontainer時看到了這個。他們說你必須避免單身。 ,因爲Singleton模式使得類(幾乎所有其他依賴於它的類)都不可測試。子類很難,或者爲Singleton類創建一個模擬對象。單身測試和子類化

但是,如果你絕對需要它,是否有測試和子類問題的解決方法?

回答

5

是什麼讓它很難測試單例是強制執行它們的單例的代碼(意思是public static MySingleton getInstance() {...}樣板)。使用反轉的控制的容器,如PicoContainer的或吉斯或Spring,刪除從對象的關注,所以現在:

  • 它可以被實例化,並有合作者插入到它在測試中沒有問題。

  • 調用單例的代碼不必知道它正在查找哪個類(它需要知道它是否必須調用靜態方法)。

我將picocontainer網站上的建議解釋爲與此類似。他們告訴你的是,讓我們的容器爲你管理組件的範圍,不要將範圍執行代碼硬連線到它們中。

+0

完全正確 - 國際奧委會是去這個東西的方式 –

1

如果你必須有單身:

  1. 有描述每個單
  2. 訪問從全局/單ServiceLocator
  3. 開啓你單身的接口在服務定位器註冊的情況下測試
期間

例如:

interface IBankApi 
{ 
    public void MakeDeposity(int accountNumber, int dollarAmount); 
    // ... 
} 

public class RealBankApi : IBankApi { ... } 

// startup code 
serviceLocator.Register<IBankApi>(new RealBankApi()); 

// code using the API 
serviceLocator.Resolve<IBankApi>().MakeDeposit(...); 

// test code setup 
class FakeBankApi : IBankApi { ... } 
serviceLocator.Register<IBankApi>(new FakeBankApi()); 
1

使用IOC(控制反轉)而不是首次使用時啓動的單例也有利於其他原因。

單線程初始化可能會遭受多線程問題(着名),其中兩個線程第一次嘗試同時訪問它。隨後的訪問可能會正確同步,但第一個訪問很難做到。

我發現使用IOC的另一個巨大優勢是在初始化時可能發生錯誤。你不希望這種情況發生在「首次使用」上,你想在早期階段知道這種故障,當然這樣處理錯誤更容易。最後,關於測試,IOC提供了一個完美的模型來隔離組件,根據需要替換組件,並以更靈活的方式將不同的組合組合在一起,從而爲單元測試和集成測試提供了完美的線索,如同作爲一個很好的回滾機制,根本不需要恢復任何代碼。

單身人士經常使用的一般原因不是爲了一性,而是爲了全球性。如果你的項目管理正確,你有一個單一的全局對象,所有其他的「註冊」(因此你的IOC模型掛起它),並可以在全球範圍內使用,同時仍然可以配置。