2012-07-02 60 views

回答

47

測試

一個原因是,單身不容易單元測試來處理。你無法控制實例化,並且它們本質上可能在調用時保持狀態。

由於這個原因,dependency injection的原則是受歡迎的。每個類都被注入(配置)它們需要運行的類(而不是通過單例訪問器派生),因此測試可以控制要使用哪些相關類實例(並在需要時提供模擬)。

像Spring這樣的框架將控制其對象的生命週期,並經常創建單例,但這些對象被框架注入到它們的依賴對象中。因此,代碼庫本身不會將對象視爲單例。

例如而比這(例如)

public class Portfolio { 
    private Calculator calc = Calculator.getCalculator(); 
} 

你會注入計算器:

public class Portfolio { 
    public Portfolio(Calculator c) { 
     this.calc = c; 
    } 
} 

因此Portfolio對象不知道如何存在Calculator的許多實例/護理。測試可以注入一個虛擬Calculator,使測試變得簡單。

併發

通過限制自己的對象的一個​​實例,用於穿線的選擇是有限的。訪問單例對象可能不得不被保護(例如,通過同步)。如果您可以維護這些對象的多個實例,那麼您可以根據您正在運行的線程定製實例數量,並增加代碼庫的併發能力。

+2

那麼,如何使用單身的人對付「測試」和「併發「問題? – Pacerier

+0

有些困難。像PowerMock這樣的工具可以提供重寫單例方法的手段,但它們是採用字節碼操作的複雜工具 –

21

我個人認爲,這違反了單一責任原則。 Singleton對象負責其目的和控制它們產生的實例的數量,我認爲這是錯誤的。

這就是爲什麼很多人將控制委託給工廠對象。

+0

我認爲這隻會使[SRP的解釋]變得可疑。 –

+0

以何種方式可疑? – MikePatel

+0

可疑的是,這顯然不是單身人士的錯,但SRP的解釋表明它是。 SRP(或對此的解釋)似乎是有罪的一方。 –

6

還有,你可能對單身許多要求:

  1. 延遲初始化;
  2. 正確處置;
  3. 作用域(例如每個線程一個)。

通常情況下,還,你就會有一大堆單身的您的應用程序,以及辛格爾頓模式不允許可重用​​的代碼。因此,如果您想要爲所有單身人士實施所有這些擔憂,您將立即看到其反模式質量。

7

單身本身不一定是一個反模式,但他們只有幾個好處,當他們用錯了成爲一個反(這經常發生)。

通常情況下,單身是不是在所有的單身人士,而是「變相全局變量」。另外,當「只有一個實例」屬性實際上不是優勢時,通常會使用它們。 (同時多次執行錯誤的事實再次平衡)。

除此之外,他們可能會非常棘手時考慮多線程來實現(通常是做了錯事或低效率),和他們失去了他們的大部分好處,如果你想控制自己的實例。

如果你想控制實例化,你需要在程序早期的某個時候手動完成,但是你也可以創建一個普通對象的實例並傳遞它。
如果銷燬順序有任何問題,您也需要手動執行此操作。主函數中的一個自動對象更簡潔,更簡單。

10

[可變]單例是一種反模式的反模式。

重要的底層反模式是全局狀態(或環境狀態)。在全球化的狀態下,你的程序中有一個很大的依賴關係博客。這確實會影響測試,但這只是不良編程影響的一部分。

在那個層次感,加上辛格爾頓在簡單地聲明可變static領域的複雜性完全沒有必要水平。

+2

易變的static領域遭受同樣的確切問題,這是全球狀態。我看不出如何使用靜態字段比單例更好。有關於此的任何信息? –

+2

@JuanMendes正如我說的,簡單的可變靜比單可變靜好,因爲他們沒有無謂的複雜性。 –

+0

我應該檢討答案留下意見以前更好。 100%同意你的觀點。它基本上是全球狀態的委婉,所以稱之爲靜態字段至少不會試圖美化它。 –

3

奇怪。看起來Singleton的錯誤實現是一種「反模式」,而不是Singleton本身。

我想我們已經忘記了每個程序都必須從某個地方開始。每一個抽象都必須有一個具體的實現,並且最終每個依賴都將最終得到解決,否則你的應用程序將無法使用。

大多數DI框架允許實例化一個類作爲一個Singleton,它只是處理,對你。如果你選擇自己做DI,注入單身並不是問題。一個Singleton IS也可以測試,如果你使用DI來注入它,不會使一個類不穩定。

IMO,像所有其他模式在那裏(包括DI和IOC)它是一個工具。有時它適合,有時它不適合。

相關問題