您好,登錄后才能下訂單哦!
什么是單例模式
所謂單例模式,就是確保某一個類只有一個實例,而且自行實例化并向整個系統提供這個實例的設計模式。單例模式是最簡單的設計模式,也是應用最廣的設計模式。一般用于避免產生多個對象消耗過多的資源或者某種類型的對象必須獨一無二的情景。
單例模式的實現方式
(1)餓漢式
單例模式極其簡單,僅有一個單例類。既然常用于確保某種類型的對象必須獨一無二的情景,那么我們可以用皇帝來舉例。代碼如下:
public class Emperor { |
從上述代碼中可以看到,類不能通過new的形式構造對象,只能用方法來獲取唯一的靜態對象。這種在聲明的時候就初始化的實現方式就叫做餓漢式。
(2)懶漢式
與餓漢式不同,懶漢式只有在第一次調用方式時才進行初始化。實現代碼如下:
public class Singleton { |
懶漢式在方法中添加了synchronized關鍵字,可以在多線程情況下確保單例對象獨一無二。但即使已經被初始化,每次調用還會進行同步,會消耗不必要的資源,并且第一次加載時進行實例化會拖慢反應速度,因此懶漢式一般不建議使用。但懶漢式并非一無是處,如果一直沒有人用的話,就不會創建實例,則是節約空間。這是以時間換空間的實現方式,與餓漢式的以空間換時間各有所長。
還記得語文老師講課外文學知識題的“禪杖就是魯智深,戒刀就是武松,板斧就是李逵”的規律嗎?注意上面代碼的getIntance()方法,實戰中見到getIntance()就是單例模式的準確率八九不離十。
(3)DCL式
Double Check Lock(以下簡稱DLC)實現單例模式既能夠在需要時才初始化對象,又能保證線程安全。代碼如下:
public class Singleton { |
DCL可以保證無論何時讀取這個變量,都是讀到內存中最新的值,無論何時寫這個變量,都可以立即寫到內存中。DCL是目前單例模式最常見的實現方式。
(4)靜態內部類式
DCL盡管能完美解決資源消耗、同步多余、線程不安全的問題,卻有低概率在并發場景比較復雜的情況下失效(少見于J2EE和Hadoop等場景,絕少見于Android場景)。因此在對性能要求極高的情況下我們可以采取靜態內部類式來實現單例模式。代碼如下:
public class Singleton {
|
靜態內部類式利用ClassLoader機制來保證初始化時僅有一個線程,不但不會造成性能損耗,還是天衣無縫的安全方式。
(5)單例模式的容器式管理
還是拿皇帝舉例子,天下可能有多個皇帝,一個軟件也可能有多個單例對象。舉唐玄宗李隆基和大燕皇帝安祿山的對立的例子不是太恰當,畢竟幾乎沒有史書認同安祿山是合法皇帝。我就舉一個大家耳熟能詳的例子——《三國演義》第80回講述了中國歷史上第一次同時存在兩位被后世的歷史學家認定為合法皇帝(曹丕和劉備)的局面,也是最著名的一次。我們先建立一個管理類:
public class EmperorManager { |
然后就可以管理多個單例對象了:
//曹丕廢帝篡炎劉 |
幾年后,孫權登基,天下又有了新的皇帝,寫法以此類推。
Android源碼中的單例模式
(1)Application
Application是Android中最典型,也是最常見的單例模式。用戶重寫Application類也只重寫一個。
(2)Activity
Activity在singleInstance啟動模式下只有一個實例,并且這個實例獨立運行在一個Task中,不允許有別的Activity存在,這也是一種單例模式。
(3)Service
Service用bindService()啟動之后,無論再啟動多少次,都只會調用onStartCommand()而不會再調用onCreate(),因為每次調用的Service都是同一對象。
(4)各種Manager
Android中有很多管理類,比如WindowManager、PowerManager、SensorManager、ActivityManager、StorageManager以及ServiceManager等等,這些管理類分別對某些資源進行操作,為了避免對同一資源的同時操作,也為了節約資源,都采取了單例模式。
(5)UID
在Picasso和Glide等框架流行起來之前,最常見的圖片加載框架非Universal-Image-Loader(以下簡稱UID)莫屬,UID的初始化方式如下:
//全局初始化此配置 |
這里又見到了熟悉的getIntance(),根據思維定式判定這是單例模式。
Android開發中如何利用單例模式
(1)當創建一個對象需要較多資源時,比如讀取配置或依賴較多其他對象時,可以用創建一個單例對象常駐內存的方式解決這個問題。
(2)當一個對象需要經常調用所以需要反復創建、銷毀時,為了減少內存開支,可以用單例模式來減少創建、銷毀該對象的資源浪費。
(3)當需要對同一個資源進行操作時(例如File I/O),可以創建一個FileManager,這樣內存里只有一個實例,避免了對同一個資源的同時操作。
需要注意的幾個問題
(1)單例模式必然有static修飾符,如果持有Activity的Context,很容易造成OOM,因此盡量使用Application的Context;此外有多少初學者在Activity銷毀時忘記銷毀視頻或地圖的單例對象而吃了大虧?
(2)在不需要獨一無二的對象的時候不要采用單例模式,譬如自定義控件就是最不適合單例模式的場景。
本系列其他博客
【設計模式與Android】建造者模式——建軍大業
【設計模式與Android】原型模式——復制中心走出來的克隆人
【設計模式與Android】工廠方法模式——化工女神的工廠
【設計模式與Android】抽象工廠模式——嵌合體克隆工廠
【設計模式與Android】策略模式——錦囊里的上策中策下策
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。