Java設計模式之單例模式及在Android中的重要使用

來源:互聯網
上載者:User

標籤:

  之前在開發中老用到一些設計模式可是呢又不是很懂,於是狠下心來琢磨一番。下面是我琢磨後總結的,希望對您有用。如果發現了問題,請幫忙指正。

一、單例模式是什嗎?

  單例模式最初的定義出現於《設計模式》:“保證一個類僅有一個執行個體,並提供一個訪問它的全域訪問點。”
  Java中單例模式定義;“一個類有且僅有一個執行個體,並且自行執行個體化向整個系統提供該執行個體。”

二、為什麼用單例模式?

  對於系統中的某些類來說,只有一個執行個體很重要。例如,一個系統中可以存在多個列印任務,但是只能有一個正在工作的任務;一個系統只有有一個視窗管理器或檔案系統;一個系統只能有一個計時工具或ID產生器。如在Windows OS 中就只能開啟一個工作管理員。如果不使用機制對視窗對象進行唯一化,將彈出多個視窗,如果這些視窗顯示的內容完全一致,則重複對象,浪費記憶體資源;如果這些視窗顯示的內容不一致,則意味著某一瞬間系統有多個狀態,與實際不符,也會為使用者帶來誤解,不知道哪一個才是真實的狀態。因此有時確保系統中某個對象的唯一性即一個類只能有一個執行個體是非常重要的。
  如何保證一個類只有一個執行個體並且這個執行個體易於被訪問呢?定義一個全域變數可以確保對象隨時都可以被訪問,但不能防止我們執行個體化多個對象。一個更好的解決辦法是讓類自身負責儲存它的唯一執行個體。這個類可以保證沒有其他執行個體被建立,並且它可以提供一個訪問該執行個體的方法。這就是單例模式的模式動機。

三、單例模式特點

單例模式特點有三個
1、單例類只能有一個執行個體。
2、單例類必須自己建立自己的唯一執行個體。
3、單例類必須給其他對象(整個系統)提供這一執行個體。
 從具體實現角度分析,一是單例模式的類只提供私人的(private)建構函式,二是類定義中含有一個該類的靜態私人(private static)對象,三是該類提供了一個靜態(static)公有的(public)函數用於建立或擷取它本身的靜態私人對象。

四、Java中幾種常見單例模式寫法

  通過上面的介紹你是不是對單例模式有了一個總的概念?沒有,那接下來繼續給你們放大招。
  基於單例模式特點,單例對象通常作為程式中存放配置資訊的載體(想想Android中的Application經常在裡面做一些配置的初始化),因為它能夠保證其他對象讀取到一致的資訊。例如在某個伺服器程式中,該伺服器的配置資訊可能存放在資料庫或 檔案中,這些配置資料由某個單例對象統一讀取,服務進程中的其他對象如果要擷取這些配置資訊,只需訪問該單例對象即可。這種方式極大地簡化了在複雜環境 下,尤其是多線程環境下的組態管理,但是隨著應用情境的不同,也可能帶來一些同步問題。

1、餓漢式單例
//餓漢式單例類.在類初始化時,已經自行執行個體化  public class Singleton {     //私人的預設構造子     private Singleton() {}     //已經自行執行個體化      private static final Singleton single = new Singleton();     //靜態Factory 方法      public static Singleton getInstance() {         return single;     } }

  上面例子中,在這個類被載入時,靜態變數single會被初始化,此時類的私人構造子會被調用。這時單例類的唯一執行個體就被構造出來了。
  餓漢式其實是一種比較形象的稱謂。既然餓,那麼在建立對象執行個體的時候就比較著急,餓了嘛,於是在裝載類的時候就建立對象執行個體—>

private static final Singleton single = new Singleton();

  餓漢式是典型的空間換時間,當類裝載時就會建立類的執行個體,不管你用不用,先建立出來,然後每次調用的時候,就不需要再判斷,節省了已耗用時間。

2、懶漢式單例
//懶漢式單例類.在第一次調用的時候執行個體化自己   public class Singleton {      private Singleton() {}      private static Singleton single=null;      //靜態Factory 方法       public static synchronized Singleton getInstance() {           if (single == null) {                 single = new Singleton();           }            return single;      }  }  

  上面的懶漢式單例類實現裡對靜態Factory 方法使用了同步化,以處理多線程環境。
  懶漢式其實是一種比較形象的稱謂。既然懶,那麼在建立對象執行個體的時候就不著急。會一直等到馬上要使用對象執行個體 的時候才會被建立,懶人嘛,總是推脫不開的時候才會真正執行工作,因此在裝載對象的時候不建立對象執行個體。

private static Singleton single=null;  

  懶漢式是典型的時間換空間,就是每次擷取執行個體都會進行判斷,看是否需要建立執行個體,浪費判斷的時間。當然,如果一直沒有人使用的話,那就不會建立執行個體,則節約記憶體空間
  由於懶漢式的實現是安全執行緒的,這樣會降低整個訪問的速度,而且每次都要判斷。那麼有沒有更好的方式實現呢?

3、雙重檢查加鎖

  可以使用“雙重檢查加鎖”的方式來實現,就可以達到實現安全執行緒,又能使效能不受很大影響。
  雙重檢查加鎖:並不是每次進入getInstance()都需要同步,而是先不同步,進入方法後,先檢查單例對象是否存在,如果不存在才進行下面的同步塊,這是第一重檢查,進入同步塊後,再次檢查執行個體是否存在,如果不存在,就在同步的情況下建立一個執行個體(單例對象),這是第二重檢查。這樣就只需要同步一次,從而減輕了多次在同步情況下進行判斷所浪費的時間。
  “雙重檢查加鎖”機制的實現會使用關鍵字volatile,它的意思是:被volatile修飾的變數的值,將不會被本地線程緩衝,所有對該變數的讀寫都是直接操作共用記憶體,從而確保多個線程能正確的處理該變數。不清楚volatile的看過來volatile解析
代碼執行個體:

public class Singleton {    private volatile static Singleton instance = null;    private Singleton(){}    public static Singleton getInstance(){        //先檢查執行個體是否存在,如果不存在才進入下面的同步塊        if(instance == null){            //同步塊,安全執行緒的建立執行個體            synchronized (Singleton.class) {                //再次檢查執行個體是否存在,如果不存在才真正的建立執行個體                if(instance == null){                    instance = new Singleton();                }            }        }        return instance;    }}

  這種實現方式既可以實現安全執行緒地建立執行個體,而又不會對效能造成太大的影響。它只是第一次建立執行個體的時候同步,以後就不需要同步了,從而加快了運行速度。
  提示:由於volatile關鍵字可能會屏蔽掉虛擬機器中一些必要的代碼最佳化,所以運行效率並不是很高。因此一般建議,沒有特別的需要,不要使用。也就是說,雖然可以使用“雙重檢查加鎖”機制來實現安全執行緒的單例,但並不建議大量採用,可以根據情況來選用。
  根據上面的分析,常見的兩種單例實現方式都存在小小的缺陷,那麼有沒有一種方案,既能實現消極式載入,又能實現安全執行緒呢?那就是下面一種方法,放大招了,接著呦。

4、靜態內部類
public class Singleton {    private Singleton(){}    /**     *    類級的內部類,也就是靜態成員式內部類,該內部類的執行個體與外部類的執行個體     *    沒有綁定關係,而且只有被調用到時才會裝載,從而實現了消極式載入。     */    private static class SingletonHolder{        /**         * 靜態初始化器,由JVM來保證安全執行緒         */        private static Singleton instance = new Singleton();    }    public static Singleton getInstance(){        return SingletonHolder.instance;    }}

當getInstance方法第一次被調用的時候,它第一次讀取SingletonHolder.instance,導致SingletonHolder類得到初始化;而這個類在裝載並被初始化的時候,會初始化它的靜態域,從而建立Singleton的執行個體,由於是靜態域,因此只會在虛擬機器裝載類的時候初始化一次,並由虛擬機器來保證它的執行緒安全性。

5、單例和枚舉
public enum Singleton {    /**     * 定義一個枚舉的元素,它就代表了Singleton的一個執行個體。     */    uniqueInstance;    /**     * 單例可以有自己的操作     */    public void singletonOperation(){        //功能處理    }}

按照《高效Java 第二版》中的說法:單元素的枚舉類型已經成為實現Singleton的最佳方法。用枚舉來實現單例非常簡單,只需要編寫一個包含單個元素的枚舉類型即可。

  對我來說,我比較喜歡第一種和第四種方式,簡單易懂。而且在JVM層實現了安全執行緒(如果不是多個類載入器環境)。一般的情況下,我會使用第一種方式,只有在要明確實現lazy loading效果時才會使用第四種方式

五、Android中典型的單例模式Application類1、Application是什嗎?

  Application和Activity,Service一樣,是android架構的一個系統組件,當android程式啟動時系統會建立一個 application對象,用來儲存系統的一些資訊。通常我們是不需要指定一個Application的,這時系統會自動幫我們建立,如果需要建立自己 的Application,也很簡單建立一個類繼承 Application並在manifest的application標籤中進行註冊(只需要給Application標籤增加個name屬性把自己的 Application的名字定入即可)。
  android系統會為每個程式運行時建立一個Application類的對象且僅建立一個,所以Application可以說是單例 (singleton)模式的一個類.且application對象的生命週期是整個程式中最長的,它的生命週期就等於這個程式的生命週期。因為它是全域 的單例的,所以在不同的Activity,Service中獲得的對象都是同一個對象。所以通過Application來進行一些,資料傳遞,資料共用 等,資料緩衝等操作。

2、巧妙運用單例模式特點,通過Application來傳遞資料

  假如有一個Activity A, 跳轉到 Activity B ,並需要推薦一些資料,通常的作法是Intent.putExtra() 讓Intent攜帶,或者有一個Bundle把資訊加入Bundle讓Intent推薦Bundle對象,實現傳遞。但這樣作有一個問題在 於,Intent和Bundle所能攜帶的資料類型都是一些基本的資料類型,如果想實現複雜的資料傳遞就比較麻煩了,通常需要實現 Serializable或者Parcellable介面。這其實是Android的一種IPC資料傳遞的方法。如果我們的兩個Activity在同一個 進程當中為什麼還要這麼麻煩呢,只要把需要傳遞的對象的引用傳遞過去就可以了。
基本思路是這樣的。在Application中建立一個HashMap ,以字串為索引,Object為value這樣我們的HashMap就可以儲存任何類型的對象了。在Activity A中把需要傳遞的對象放入這個HashMap,然後通過Intent或者其它途經再把這索引的字串傳遞給Activity B ,Activity B 就可以根據這個字串在HashMap中取出這個對象了。只要再向下轉個型 ,就實現了對象的傳遞。

六、總結

經過網上的爬文終於瞭解了什麼是單例模式,在這裡感謝
http://www.cnblogs.com/java-my-life/archive/2012/03/31/2425631.html
http://blog.csdn.net/songylwq/article/details/6058771
http://www.blogjava.net/kenzhh/archive/2013/03/15/357824.html
http://www.cnblogs.com/hxsyl/archive/2013/03/19/2969489.html
http://blog.csdn.net/pi9nc/article/details/11200969

Java設計模式之單例模式及在Android中的重要使用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.