1. 程式人生 > >Android中的單例模式使用場景

Android中的單例模式使用場景

1.設計模式例項-單例模式

單例模式,故名思議,是指在一個類中通過設定靜態使得其僅創造一個唯一的例項。這樣設定的目的是滿足開發者的希望??這個類只需要被例項化建立一次,同時因為其為靜態的緣故,載入的速度也應該快於正常例項化一個類的速度(理論上)。

在Android開發中,當我們需要建立一個Fragment的時候常常會用到這樣的模式,沒有程式碼的學習是虛無的,接下來亮程式碼學習:

public class SelectFrame extends Fragment {

  private final static String selectFrameKey = "SFKey";
  private static SelectFrame mSelectFrame;
  private ArrayList<String> frameList;
  public static SelectFrame getInstance(ArrayList<String> frameList){
    if (mSelectFrame == null) {
      mSelectFrame = new SelectFrame();
    }
    Bundle bundle = new Bundle();
    bundle.putStringArrayList(selectFrameKey, frameList);
    mSelectFrame.setArguments(bundle);
    return mSelectFrame;
  }
......


這是我在一個Fragment類裡面定義的其中一部分,首先必須要定義一個自身的靜態mSelectFrame。然後通過一個靜態方法 getInstance()來例項化這個mSelectFrame,很明顯,這裡通過判斷其是否為空的方式,使得每一次我們使用getInstance的時候都返回的是同一個物件mSelectFrame。

getInstance方法中有時我們也會放入一些我們需要傳遞的引數,比如我這個方法中放入了一個List物件,然後直接在裡面用Bundle裝載這個List物件,原本我們可能是在外部來做這些操作的,然而現在卻直接通過這個方法將資料傳入的操作整合到了這個Fragment中,即減少了外部Activity的邏輯程式碼,也使得這個Fragment在複用的時候操作更方便。(再通過setArguments的方法儲存資料)。

接下來看我們的onCreateView方法:

  @Override
  public View onCreateView(LayoutInflater inflater,
      @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.select_frame_fragment, container, false);
    Bundle bundle = mSelectFrame.getArguments();
    frameList = bundle.getStringArrayList(selectFrameKey);
}
這裡我們就將從前面getInstance中setArguments儲存下來的資料通過Fragment的getArguments方法重新將資料讀取出來。這樣就完成了我們的目的。

接下來就是在Activity中建立我們這個Fragment物件了:

    selectFrameFrag = SelectFrame.getInstance(nameFrameThumbnail);
    fm.beginTransaction().add(R.id.fragment_frame_container, selectFrameFrag).commit();
(fm是FragmentManager..)

這樣就OK了。

2.單例模式的分類

單例模式有兩種建立方式,分別為餓漢式和懶漢式。

餓漢式,故名思議,很餓,在一開始就直接建立了這個物件。

懶漢式,顧名思義,很懶,只有在你要呼叫它的時候,通過自己寫的方法裡面來對他例項化。剛剛上面那個例子就是懶漢式的。

也許這麼說你會有一點不明白(其實應該沒有人不明白吧= =),然後其實只要看程式碼的這個地方:

  private static SelectFrame mSelectFrame;

上面這個程式碼,這裡一開始定義自身的靜態時,沒有例項化它,那麼就是個懶漢.然後只有在我呼叫getInstance方法的時候,才在裡面對他進行例項化(new SelectFrame()).

然後我們再看看餓漢:

  private static SelectFrame mSelectFrame = new SelectFrame();

在定義的時候就已經例項化了.

3.單例模式的執行緒安全問題

沒錯,單例模式畢竟就是像上面講的這麼簡單。但需要注意的是,單例模式中的餓漢式是執行緒安全的,而懶漢式是執行緒不安全的,我們一般會再懶漢式的getInstance方法中通過synchronized上鎖。類似於這樣:

    if (mSelectFrame == null) {
      synchronized (SelectFrame.class) {
        if (mSelectFrame == null) {
          mSelectFrame = new SelectFrame();
        }
      }
    }

有人說為什麼要用兩個if XX == null。這裡是因為提高效率,只有一個也是可以的,但效率上大大減低,因為不是每一次呼叫的時候我們要判斷他是否同步,應該是如果判斷當前為null的話,我們就直接不讓他進入了,不需要判斷是否同步。只有滿足第一個條件的時候,我們才需要用鎖來判斷它是否執行緒安全。(這裡的意思也是說明if一條語句的判斷速度當然比synchronized (SelectFrame.class)快。。)

另外,在我們使用單例模式的時候,有些人會去私有化這個類的構造方法,使得這個類只能通過自己寫的getInstance()來建立。類似於這樣:

  private SelectFrame() {
    // 並不需要做什麼,只需要將這個外面的public改成private就好了=。=
  }

嗯嗯,這麼一來外部就只能按我要求的方法來建立這個物件了.

在這裡也基本將單例模式的使用基本講完了,接下來還會繼續寫其他的設計模式的使用,如果有涉及到Android上的都會盡力用Android上的例子來講,加深印象。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

單例模式是最常用到的設計模式之一,熟悉設計模式的朋友對單例模式都不會陌生。一般介紹單例模式的書籍都會提到 餓漢式懶漢式這兩種實現方式。但是除了這兩種方式,本文還會介紹其他幾種實現單例的方式,讓我們來一起看看吧。

簡介

單例模式是一種常用的軟體設計模式,其定義是單例物件的類只能允許一個例項存在。

許多時候整個系統只需要擁有一個的全域性物件,這樣有利於我們協調系統整體的行為。比如在某個伺服器程式中,該伺服器的配置資訊存放在一個檔案中,這些配置資料由一個單例物件統一讀取,然後服務程序中的其他物件再通過這個單例物件獲取這些配置資訊。這種方式簡化了在複雜環境下的配置管理。

基本的實現思路

單例模式要求類能夠有返回物件一個引用(永遠是同一個)和一個獲得該例項的方法(必須是靜態方法,通常使用getInstance這個名稱)。

單例的實現主要是通過以下兩個步驟:

  1. 將該類的構造方法定義為私有方法,這樣其他處的程式碼就無法通過呼叫該類的構造方法來例項化該類的物件,只有通過該類提供的靜態方法來得到該類的唯一例項;
  2. 在該類內提供一個靜態方法,當我們呼叫這個方法時,如果類持有的引用不為空就返回這個引用,如果類保持的引用為空就建立該類的例項並將例項的引用賦予該類保持的引用。

注意事項

單例模式在多執行緒的應用場合下必須小心使用。如果當唯一例項尚未建立時,有兩個執行緒同時呼叫建立方法,那麼它們同時沒有檢測到唯一例項的存在,從而同時各自建立了一個例項,這樣就有兩個例項被構造出來,從而違反了單例模式中例項唯一的原則。 解決這個問題的辦法是為指示類是否已經例項化的變數提供一個互斥鎖(雖然這樣會降低效率)。

單例模式的八種寫法

1、餓漢式(靜態常量)[可用]

public class Singleton {
    private final static Singleton INSTANCE = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return INSTANCE;
    }
}

優點:這種寫法比較簡單,就是在類裝載的時候就完成例項化。避免了執行緒同步問題。

缺點:在類裝載的時候就完成例項化,沒有達到Lazy Loading的效果。如果從始至終從未使用過這個例項,則會造成記憶體的浪費。

2、餓漢式(靜態程式碼塊)[可用]

public class Singleton {
    private static Singleton instance;
    static {
        instance = new Singleton();
    }
    private Singleton() {}
    public Singleton getInstance() {
        return instance;
    }
}

這種方式和上面的方式其實類似,只不過將類例項化的過程放在了靜態程式碼塊中,也是在類裝載的時候,就執行靜態程式碼塊中的程式碼,初始化類的例項。優缺點和上面是一樣的。

3、懶漢式(執行緒不安全)[不可用]

public class Singleton {
    private static Singleton singleton;
    private Singleton() {}
    public static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

這種寫法起到了Lazy Loading的效果,但是隻能在單執行緒下使用。如果在多執行緒下,一個執行緒進入了if (singleton == null)判斷語句塊,還未來得及往下執行,另一個執行緒也通過了這個判斷語句,這時便會產生多個例項。所以在多執行緒環境下不可使用這種方式。

4、懶漢式(執行緒安全,同步方法)[不推薦用]

public class Singleton {
    private static Singleton singleton;
    private Singleton() {}
    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

解決上面第三種實現方式的執行緒不安全問題,做個執行緒同步就可以了,於是就對getInstance()方法進行了執行緒同步。

缺點:效率太低了,每個執行緒在想獲得類的例項時候,執行getInstance()方法都要進行同步。而其實這個方法只執行一次例項化程式碼就夠了,後面的想獲得該類例項,直接return就行了。方法進行同步效率太低要改進。

5、懶漢式(執行緒安全,同步程式碼塊)[不可用]

public class Singleton {
    private static Singleton singleton;
    private Singleton() {}
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                singleton = new Singleton();
            }
        }
        return singleton;
    }
}

由於第四種實現方式同步效率太低,所以摒棄同步方法,改為同步產生例項化的的程式碼塊。但是這種同步並不能起到執行緒同步的作用。跟第3種實現方式遇到的情形一致,假如一個執行緒進入了if (singleton == null)判斷語句塊,還未來得及往下執行,另一個執行緒也通過了這個判斷語句,這時便會產生多個例項。

6、雙重檢查[推薦用]

public class Singleton {
    private static volatile Singleton singleton;
    private Singleton() {}
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

Double-Check概念對於多執行緒開發者來說不會陌生,如程式碼中所示,我們進行了兩次if (singleton == null)檢查,這樣就可以保證執行緒安全了。這樣,例項化程式碼只用執行一次,後面再次訪問時,判斷if (singleton == null),直接return例項化物件。

優點:執行緒安全;延遲載入;效率較高。

7、靜態內部類[推薦用]

public class Singleton {
    private Singleton() {}
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

這種方式跟餓漢式方式採用的機制類似,但又有不同。兩者都是採用了類裝載的機制來保證初始化例項時只有一個執行緒。不同的地方在餓漢式方式是隻要Singleton類被裝載就會例項化,沒有Lazy-Loading的作用,而靜態內部類方式在Singleton類被裝載時並不會立即例項化,而是在需要例項化時,呼叫getInstance方法,才會裝載SingletonInstance類,從而完成Singleton的例項化。

類的靜態屬性只會在第一次載入類的時候初始化,所以在這裡,JVM幫助我們保證了執行緒的安全性,在類進行初始化時,別的執行緒是無法進入的。

優點:避免了執行緒不安全,延遲載入,效率高。

8、列舉[推薦用]

public enum Singleton {
    INSTANCE;
    public void whateverMethod() {
    }
}

藉助JDK1.5中新增的列舉來實現單例模式。不僅能避免多執行緒同步問題,而且還能防止反序列化重新建立新的物件。可能是因為列舉在JDK1.5中才新增,所以在實際專案開發中,很少見人這麼寫過。

優點

系統記憶體中該類只存在一個物件,節省了系統資源,對於一些需要頻繁建立銷燬的物件,使用單例模式可以提高系統性能。

缺點

當想例項化一個單例類的時候,必須要記住使用相應的獲取物件的方法,而不是使用new,可能會給其他開發人員造成困擾,特別是看不到原始碼的時候。

適用場合

  • 需要頻繁的進行建立和銷燬的物件;
  • 建立物件時耗時過多或耗費資源過多,但又經常用到的物件;
  • 工具類物件;
  • 頻繁訪問資料庫或檔案的物件。

相關推薦

Android模式的應用

單例模式在我們日常開發中或多或少都會遇見,使用場景也是多種多樣。今天根據專案中需求,正好用到了單例模式。在此記錄一下。 一、跟隨app存活 有什麼方式,可以讓一個變數跟隨app存活呢?是一個單例模式維護的靜態工具類。靜態工具類程式碼一般都使用單例模式來實現,可以防止建立多

android模式的優缺點

    本篇文章主要介紹android開發中常用的單例模式和其中的幾種寫法,分析介紹在安卓開發中單例模式的優缺點。一、常見的幾種單例模式    首先來回顧一下幾種常見的單例模式,分析一下個自的優缺點    1.懶漢式    //懶漢式單例類.在第一次呼叫的時候例項化自己   

Python設計模式模式的實現及在Tornado的應用

實例 類變量 attribute rap all wrap 線程 ++ 出現 單例模式的實現方式 將類實例綁定到類變量上 class Singleton(object): _instance = None def new(cls, *args): if not isinst

python模式的執行緒安全問題

看了好多文章都是java實現的,特此寫一篇python的。 這個問題的兩種解決方案: 1.最簡單粗暴的就是在系統中先生成一個單例,就不存線上程安全問題了 2.用雙重同步鎖去實現,一把鎖加外面,一把鎖加里面: class Singleton(object): __instance

java模式

單例模式屬於設計模式中的一種,使用單例模式的類允許只存在一個物件例項。在java開發中,有好多種不同單例模式的寫法,而且運用的場景也各不相同,因此在java面試中屬於高頻考點,面試官會讓面試者手寫單例模式程式碼,所以提醒大家特別注意下。 這裡我就記錄下常見的幾種單例模式寫法:

Android模式的N種實現方式

推薦書籍:《Android原始碼設計模式 第二版》 單例模式的定義及使用場景 定義:確保某個類只有一個例項,而且自行例項化提供給外部使用。 使用場景:某個型別的物件只應該有且只有一個,或者避免建立多個物件消耗過多的資源時。如:訪問IO或資料庫時要考慮單例模式。 N種實現方式及比較&n

Python模式的實現方式

在 Python 中,我們可以用多種方法來實現單例模式: 使用模組 使用 new 使用裝飾器(decorator) 使用元類(metaclass) 使用模組 一、其實,Python 的模組就是天然的單例模式,因為模組在第一次匯入時,會生成 .pyc 檔案,當第二

Android-Java模式

今天我們來說說一個非常常用的模式,單例模式,單例模式讓某個類中有自己的例項,而且只例項化一次,避免重複例項化,單例模式讓某個類提供了全域性唯一訪問點,如果某個類被其他物件頻繁使用,就可以考慮單例模式,以下用程式碼來分析: 餓漢式單例模式舉例: /* * 餓漢式單例模式 * 餓漢式的這種單例模

PHP模式實現

  class SingleInstance{                private function _construct(){                    }               private static $instance;              private fun

【設計模式Android模式——獨一無二的皇帝

什麼是單例模式 所謂單例模式,就是確保某一個類只有一個例項,而且自行例項化並向整個系統提供這個例項的設計模式。單例模式是最簡單的設計模式,也是應用最廣的設計模式。一般用於避免產生多個物件消耗過多的資

Java模式的七種寫法

第一種(懶漢,執行緒不安全): Java程式碼 public class Singleton {      private static Singleton instance;      private Singleton (){}      public s

android模式:懶漢式和餓漢式的區別

單例模式:懶漢式和餓漢式    餓漢式:執行緒安全:構造方法私有化:推薦使用          public class Singleton{            private static Si

Java模式與簡單工廠模式的簡單例項介紹

1:單例設計模式 單例模式也稱為單件模式、單子模式,可能是使用最廣泛的設計模式。其目的是保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點,該例項被所有程式模組共享。單例模式又包含 餓漢式和懶漢式

Java模式之餓漢式和懶漢式

單例模式顧名思義,就是隻能建立一個物件,這裡就限制了它的構造方法,不能隨便new了。所以用構造方法用private修飾。餓漢式和懶漢式通過名字也是可以區分的。餓漢式,餓了就主動去找食物了,就直接主動建立一個物件。然後通過公共的方法暴露給外部呼叫。懶漢式,懶了就用的時候再去建立

7模式實現小結

原子 vol 暫時 socket static data instance 改進 cli import java.net.Socket; import java.sql.Connection; public class Test { public st

面試模式有幾種寫法

“你知道茴香豆的‘茴’字有幾種寫法嗎?” 糾結單例模式有幾種寫法有用嗎?有點用,面試中經常選擇其中一種或幾種寫法作為話

設計模式-模式(Singleton)在Android的應用場景和實際使用遇到的問題

介紹 在上篇部落格中詳細說明了各種單例的寫法和問題。這篇主要介紹單例在Android開發中的各種應用場景以及和靜態類方法的對比考慮,舉實際例子說明。 單例的思考 寫了這麼多單例,都快忘記我們到底為什麼需要單例,複習單例的本質 單例的本質:控制例

Android模式使用場景

1.設計模式例項-單例模式 單例模式,故名思議,是指在一個類中通過設定靜態使得其僅創造一個唯一的例項。這樣設定的目的是滿足開發者的希望??這個類只需要被例項化建立一次,同時因為其為靜態的緣故,載入的速度也應該快於正常例項化一個類的速度(理論上)。 在Android開發中,當

android開發學習 ------- 【轉】 android模式 (詳解)

lan post tail -- and 使用 href details android開發 https://blog.csdn.net/u011418943/article/details/60139644 這篇文章 前因後果 都說出來了 ,值得學習。 htt

Android模式(包含Java、Kotlin)

  在Android開發工程中,單例模式可以說是我們使用得非常頻繁的設計模式了。常見的寫法有5種: 餓漢式 懶漢式 同步鎖 雙重校驗 內部類 下面我們對這5種寫法的Java、Kotlin各自舉例。呼叫統一由Kotlin呼叫(其實差別並不大) 一、餓漢式 java