2010-05-04 92 views
68

我從來沒有找到關於幫助程序/實用程序類的這些簡單問題的好答案:爲什麼使用單例而不是靜態方法?

爲什麼我要創建一個單例(無狀態)而不是使用靜態方法?

如果一個對象沒有狀態,爲什麼需要一個對象實例?

+0

http://stackoverflow.com/questions/720744/static-class-and-singleton – 2010-05-04 12:54:09

+0

可能的重複不要以爲我們談論2種不同的語言,所以答案可能會有所不同,但感謝您的鏈接,在java從來沒有聽說過「monostate」這個詞 – 2011-12-09 09:52:23

回答

64

一個單例用於將某種全局狀態引入到應用程序中。如果是無狀態的,我還沒有看到使用單點,除非

  • 您希望將其與狀態,你需要一個對象實例對於一些特定的可預見的未來或
  • 延長技術原因(例如,對於C#lock聲明,雖然這已經很牽強了)或
  • 您需要繼承,即您希望能夠輕鬆地用另一個使用相同接口替換您的單身人士但是不同的實現。例如,Java中的Toolkit.getDefaultToolkit()方法將返回一個確切類型與系統相關的單例。
+23

我要去+1,儘管恕我直言的單身人士是濫用**引入全球國家。單例的目的不是使對象全局可用,而是強制對象僅實例化一次。全局對象是一個必要的邪惡。除非真正需要,否則應該儘量不要使用它們,因爲它們通常會導致高耦合性,而SomeSingleton.getInstance()。someMethod()遍佈整個地方。:) – back2dos 2010-05-04 12:19:32

+0

對於只需一個渲染實例而不是多個渲染實例的遊戲,或者在網絡管道類中設置安全通道,一次只能有一個連接的情況下,它非常有用。 – Tschallacka 2015-05-19 11:14:43

+2

「輕鬆取代你的單身人士」部分是我認爲最重要的一點。 Rest非常接近靜態類的實現。 – 2016-03-14 14:47:16

34

我可以看到使用無狀態單例代替靜態方法類的情況,即Dependency Injection

如果您有一個直接使用的輔助函數類的實用函數,它會創建一個隱藏的依賴關係;你無法控制誰可以使用它或在哪裏。通過無狀態單例實例注入相同的幫助類,可以控制它在何處以及如何使用,並在需要時替換/模擬它等。

使它成爲一個單例實例可以簡單地確保您不再需要分配更多類型的對象(因爲您只需要一個)。

+1

*「你無法控制誰可以使用它,或者在哪裏。」*爲什麼有人需要它? – hagrawal 2015-07-16 20:19:02

+0

@hagrawal爲了測試目的,你應該可以模擬它 – 2016-12-08 10:26:58

5

在大多數編程語言中,類沒有涉及很多類型系統。雖然一個類,其靜態方法和變量是一個對象,但它往往不能實現一個接口或擴展其他類。因爲這個原因,它不能以多態的方式使用,因爲它不能是另一種類型的子類型。例如,如果您有一個接口IFooable,這是其他類別的多個方法簽名所要求的,則類對象StaticFoo不能用於代替IFooable,而FooSingleton.getInstance()可以(假設FooSingleton執行IFooable)。

請注意,正如我評論Heinzi的回答,單身人士是控制實例化的模式。它將new Class()替換爲Class.getInstance(),這使Class的作者可以更好地控制實例,可以使用它來防止創建不必要的實例。單身人士只是工廠模式的一個非常特殊的例子,應該這樣對待。常見使用使得它成爲全球註冊局的特例,而這往往會導致糟糕的結果,因爲全球註冊局不應該被無情地使用。

如果您打算提供全局幫助函數,那麼靜態方法將工作得很好。該類不會充當類,而只是作爲一個名稱空間。我建議,你保持高凝聚力,否則你可能會遇到最古怪的耦合問題。

格爾茨
back2dos

0

辛格爾頓不是無狀態的,它擁有全局狀態。

,我可以想到用辛格爾頓的部分原因是:

  • 以避免內存泄漏
  • 提供所有模塊相同的狀態在一個應用程序如數據庫連接
+0

我知道,但實際上單身可以或多或少是無狀態的......如果它不共享任何類屬性... – 2010-05-04 14:39:52

11

其實我我們發現了另一個沒有提到的答案:靜態方法很難測試。

似乎大多數測試框架對於嘲笑實例方法非常有用,但其中許多框架並沒有以一種體面的方式處理靜態方法的模擬。

+2

但Powermock似乎能夠這樣做 – 2012-03-23 10:11:58

2

使用哪一個之間有一個折衷。單身人士可能有也可能沒有狀態,他們指的是對象。如果他們不保持狀態並且僅用於全局訪問,那麼靜態更好,因爲這些方法會更快。但是如果你想利用對象和OOP概念(繼承多態),那麼單例更好。

考慮一個例子:java.lang.Runtime是java中的單例類。這個類允許每個JVM有不同的實現。該實現對於每個JVM都是單個實現。如果這個類是靜態的,我們不能通過基於JVM的不同實現。

我發現這個鏈接真的有用:http://javarevisited.blogspot.com/2013/03/difference-between-singleton-pattern-vs-static-class-java.html

希望它有幫助!

+0

這個答案很適合在現實世界中包含一個具體的例子。 – systemovich 2016-11-14 14:00:56

1

對我來說「想對象狀態使用辛格爾頓,要獲取函數使用靜態方法」

這取決於你想要什麼。無論何時您想要對象狀態(例如多態性爲空狀態而不是null或默認狀態),單例對您來說都是合適的選擇,而靜態方法在您需要函數時使用(接收輸入然後返回輸出)。

我推薦單例情況下,它應該始終是實例化後的相同狀態。它不應該是可克隆的,也不能接收任何設置值(除了來自文件的靜態配置,例如屬性文件在java中)。

P.S.這兩者之間的性能在毫秒級上有所不同,所以首先關注架構

相關問題