1. 程式人生 > >程式設計之單例模式VS靜態方法

程式設計之單例模式VS靜態方法

原文:https://blog.csdn.net/johnny901114/article/details/11969015?utm_source=copy 

我們在設計程式經常會有這種需求 , 某個類裡的方法能夠全域性訪問. 在這種情況下有兩種實現方案 : 

1>單例模式(Singleton);

2>靜態方法.

但是, 對於這兩種實現方式 , 那種更好呢?

在國內論壇上看了一下其他的一些看法 : 

http://hi.baidu.com/jiangzhong8715/item/c8b66e3d6afd2f677c034b07 : 

關於這個問題,下面是一些同仁的觀點: 
觀點一:(單例) 
單例模式比靜態方法有很多優勢: 
首先,單例可以繼承類,實現介面,而靜態類不能(可以整合類,但不能整合例項成員); 
其次,單例可以被延遲初始化,靜態類一般在第一次載入是初始化; 
再次,單例類可以被整合,他的方法可以被覆寫; 
最後,或許最重要的是,單例類可以被用於多型而無需強迫使用者只假定唯一的例項。舉個例子,你可能在開始時只寫一個配置,但是以後你可能需要支援超過一個配置集,或者可能需要允許使用者從外部從外部檔案中載入一個配置物件,或者編寫自己的。你的程式碼不需要關注全域性的狀態,因此你的程式碼會更加靈活。
觀點二:(靜態方法) 
靜態方法中產生的物件,會隨著靜態方法執行完畢而釋放掉,而且執行類中的靜態方法時,不會例項化靜態方法所在的類。如果是用singleton, 產生的那一個唯一的例項,會一直在記憶體中,不會被GC清除的(原因是靜態的屬性變數不會被GC清除),除非整個JVM退出了。這個問題我之前也想幾天,並且自己寫程式碼來做了個實驗。

觀點三:(Good!) 
由於DAO的初始化,會比較佔系統資源的,如果用靜態方法來取,會不斷地初始化和釋放,所以我個人認為如果不存在比較複雜的事務管理,用singleton會比較好。個人意見,歡迎各位高手指正。 
總結:大家對這個問題都有一個共識:那就是例項化方法更多被使用和穩妥,靜態方法少使用。 
有時候我們對靜態方法和例項化方法會有一些誤解。 
1、大家都以為“ 靜態方法常駐記憶體,例項方法不是,所以靜態方法效率高但佔記憶體。” 
事實上,他們都是一樣的,在載入時機和佔用記憶體上,靜態方法和例項方法是一樣的,在型別第一次被使用時載入。呼叫的速度基本上沒有差別。 
2、大家都以為“ 靜態方法在堆上分配記憶體,例項方法在堆疊上” 
事實上所有的方法都不可能在堆或者堆疊上分配記憶體,方法作為程式碼是被載入到特殊的程式碼記憶體區域,這個記憶體區域是不可寫的。 
方法佔不佔用更多記憶體,和它是不是static沒什麼關係。  
因為欄位是用來儲存每個例項物件的資訊的,所以欄位會佔有記憶體,並且因為每個例項物件的狀態都不一致(至少不能認為它們是一致的),所以每個例項物件的所以欄位都會在記憶體中有一分拷貝,也因為這樣你才能用它們來區分你現在操作的是哪個物件。 
但方法不一樣,不論有多少個例項物件,它的方法的程式碼都是一樣的,所以只要有一份程式碼就夠了。因此無論是static還是non-static的方法,都只存在一份程式碼,也就是隻佔用一份記憶體空間。 
同樣的程式碼,為什麼執行起來表現卻不一樣?這就依賴於方法所用的資料了。主要有兩種資料來源,一種就是通過方法的引數傳進來,另一種就是使用class的成員變數的值…… 

3、大家都以為“例項方法需要先建立例項才可以呼叫,比較麻煩,靜態方法不用,比較簡單” 
事實上如果一個方法與他所在類的例項物件無關,那麼它就應該是靜態的,而不應該把它寫成例項方法。所以所有的例項方法都與例項有關,既然與例項有關,那麼建立例項就是必然的步驟,沒有麻煩簡單一說。
當然你完全可以把所有的例項方法都寫成靜態的,將例項作為引數傳入即可,一般情況下可能不會出什麼問題。 
從面向物件的角度上來說,在抉擇使用例項化方法或靜態方法時,應該根據是否該方法和例項化物件具有邏輯上的相關性,如果是就應該使用例項化物件 反之使用靜態方法。這只是從面向物件角度上來說的。
如果從執行緒安全、效能、相容性上來看 也是選用例項化方法為宜。 
我們為什麼要把方法區分為:靜態方法和例項化方法 ? 
如果我們繼續深入研究的話,就要脫離技術談理論了。早期的結構化程式設計,幾乎所有的方法都是“靜態方法”,引入例項化方法概念是面向物件概念出現以後的事情了,區分靜態方法和例項化方法不能單單從效能上去理解,建立c++,java,c#這樣面嚮物件語言的大師引入例項化方法一定不是要解決什麼效能、記憶體的問題,而是為了讓開發更加模式化、面向物件化。這樣說的話,靜態方法和例項化方式的區分是為了解決模式的問題。
拿別人一個例子說事: 
比如說“人”這個類,每個人都有姓名、年齡、性別、身高等,這些屬性就應該是非靜態的,因為每個人都的這些屬性都不相同;但人在生物學上屬於哪個門哪個綱哪個目等,這個屬性是屬於整個人類,所以就應該是靜態的——它不依賴與某個特定的人,不會有某個人是“脊椎動物門哺乳動物綱靈長目”而某個人卻是“偶蹄目”的  

在國外一些論壇的看法(重點) : 

http://javarevisited.blogspot.com/2013/03/difference-between-singleton-pattern-vs-static-class-java.html

但是該連線好像只能翻牆才能檢視. 故再次給大家做一個翻譯(翻譯的不好之處請多批評指正) : 

在這邊文章中有兩個術語 : 單例和靜態類(所有的方法成員都是靜態的) , 下面只給大家說說該文章的重點 : 

1>什麼時候使用靜態類代替singleton : 

這裡有幾個很好的靜態類比singleton更好的應用場景. 最基本的例子就是在Java中的java.lang.Math類的實現方式, Math類就是用過靜態方法來實現的,而不是單例來實現的.

總結 : 

如果你的singleton不提維持任何狀態, 僅僅是提供全域性的訪問 , 這個時候就適合用靜態類 , 這樣速度也更快, 因為static bind在編譯期間(compile during) . 記住不經意維持子類的狀態 , 尤其是在併發的情況下, 多個執行緒併發修改,這容易導致不容易發現的race condition 關於race condition .

靜態類適用於一些工具類 , 其他的如單個訪問資源就可以用singleton.

2>靜態類和singleton之間的區別 : 

① static類有更好的訪問效率(Static class provides better performance than Singleton pattern, because static methods are bonded on compile time)

③ singleton比static class更容易測試. 那個容易模擬(mock), 哪個就容易測試. singleton很容易用JUnit測試, 因為你能夠傳遞mock物件, 當singleton需要的時候(作為方法引數或者建構函式引數),

④ 如果你的需求是維護(maintain)狀態, 那麼singleton比static class更好 , 如果使用static class會出現一些問題.

⑤ singleton支援延遲載入 , 而static class 則不支援這樣的特性 , 在重量級的物件, 延遲載入就顯得非常重要.

⑥ 在一些依賴注入(Dependency injection framework)的框架 , 它能夠很好的管理singleton物件 . 例如Spring.

3>singleton相對於靜態類的一些高階特點 : 

singleton 對於static class 主要的優點是更加面向物件 . 對於singleton你可以使用繼承(Inheritance)和多型(polymorphism)來繼承一個基類, 實現一個介面, 提供不同功能 的實現. 例如 , Java中java.lang.Runtime ,該類就是一個singleton的, 呼叫getRuntime(),基於不同的JVM ,返回不同的實現物件, 針對一個一個JVM,確保只有一個Runtime物件 , 如果使用static class就不能很好的來實現這樣的功能了 .