<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經(jīng)轉(zhuǎn)移至github,大家請訪問 http://qaseven.github.io/

    Java模式設(shè)計之單例模式

     在Java程序設(shè)計中經(jīng)常會用到單例模式,但是很多時候程序員卻不知道什么時候該使用單例模式,或者怎么使用單例模式。
      我們總結(jié)分析單例模式的時候,了解到單例模式的要點有三個:一是某個類只能有一個實例;二是它必須自行創(chuàng)建這個事例;三是它必須自行向整個系統(tǒng)提供這個實例。在下面的對象圖中,有一個"單例對象",而"客戶甲"、"客戶乙"和"客戶丙"是單例對象的三個客戶對象。可以看到,所有的客戶對象共享一個單例對象。而且從單例對象到自身的連接線可以看出,單例對象持有對自己的引用。
      單例模式在資源管理器中應用。
      一些資源管理器常常設(shè)計成單例模式。
      在計算機系統(tǒng)中,需要管理的資源包括軟件外部資源,譬如每臺計算機可以有若干個打印機,但只能有一個Printer Spooler, 以避免兩個打印作業(yè)同時輸出到打印機中。每臺計算機可以有若干傳真卡,但是只應該有一個軟件負責管理傳真卡,以避免出現(xiàn)兩份傳真作業(yè)同時傳到傳真卡中的情況。每臺計算機可以有若干通信端口,系統(tǒng)應當集中管理這些通信端口,以避免一個通信端口同時被兩個請求同時調(diào)用。
      需要管理的資源包括軟件內(nèi)部資源,譬如,大多數(shù)的軟件都有一個(甚至多個)屬性(properties)文件存放系統(tǒng)配置。這樣的系統(tǒng)應當由一個對象來管理一個屬性文件。
      需要管理的軟件內(nèi)部資源也包括譬如負責記錄網(wǎng)站來訪人數(shù)的部件,記錄軟件系統(tǒng)內(nèi)部事件、出錯信息的部件,或是對系統(tǒng)的表現(xiàn)進行檢查的部件等。這些部件都必須集中管理,不可政出多頭。
      這些資源管理器構(gòu)件必須只有一個實例,這是其一;它們必須自行初始化,這是其二;允許整個系統(tǒng)訪問自己這是其三。因此,它們都滿足單例模式的條件,是單例模式的應用。
      分析單例模式的結(jié)構(gòu)。
      單例模式有以下的特點:
      1、單例類只可有一個實例。
      2、單例類必須自己創(chuàng)建自己這惟一的實例。
      3、單例類必須給所有其他對象提供這一實例。雖然單例模式中的單例類被限定只能有一個實例,但是單例模式和單例類可以很容易被推廣到任意且有限多個實例的情況,這時候稱它為多例模式(Multiton Pattern) 和多例類(Multiton Class)。
      由于Java 語言的特點,使得單例模式在Java 語言的實現(xiàn)上有自己的特點。這些特點主要表現(xiàn)在單例類如何將自己實例化上。
      餓漢式單例類
      這是在Java 語言里實現(xiàn)得最為簡便的單例類,下面所示的類圖描述了一個餓漢式單例類的典型實現(xiàn)。
      從圖中可以看出,此類已經(jīng)自已將自己實例化。
      代碼清單1:餓漢式單例類
    public class EagerSingleton
    {
    private static final EagerSingleton m_instance =
    new EagerSingleton();
    /**
    * 私有的默認構(gòu)造子
    */
    private EagerSingleton() { }
    /**
    * 靜態(tài)工廠方法
    */
    public static EagerSingleton getInstance()
    {
    return m_instance;
    }
    }
      讀者可以看出,在這個類被加載時,靜態(tài)變量m_instance 會被初始化,此時類的私有構(gòu)造子會被調(diào)用。這時候,單例類的惟一實例就被創(chuàng)建出來了。
      Java 語言中單例類的一個最重要的特點是類的構(gòu)造子是私有的,從而避免外界利用構(gòu)造子直接創(chuàng)建出任意多的實例。值得指出的是,由于構(gòu)造子是私有的,因此,此類不能被繼承。

     懶漢式單例類
      與餓漢式單例類相同之處是,類的構(gòu)造子是私有的。與餓漢式單例類不同的是,懶漢式單例類在第一次被引用時將自己實例化。如果加載器是靜態(tài)的,那么在懶漢式單例類被加載時不會將自己實例化。如下圖所示,類圖中給出了一個典型的餓漢式單例類實現(xiàn)。
      代碼清單2:懶漢式單例類
    package com.javapatterns.singleton.demos;
    public class LazySingleton
    {
    private static LazySingleton
    m_instance = null;
    /**
    * 私有的默認構(gòu)造子,保證外界無法直接實例化
    */
    private LazySingleton() { }
    /**
    * 靜態(tài)工廠方法,返還此類的惟一實例
    */
    synchronized public static LazySingleton
    getInstance()
    {
    if (m_instance == null)
    {
    m_instance = new LazySingleton();
    }
    return m_instance;
    }  }
      同樣,由于構(gòu)造子是私有的,因此,此類不能被繼承。餓漢式單例類在自己被加載時就將自己實例化。即便加載器是靜態(tài)的,在餓漢式單例類被加載時仍會將自己實例化。單從資源利用效率角度來講,這個比懶漢式單例類稍差些。
      從速度和反應時間角度來講,則比懶漢式單例類稍好些。然而,懶漢式單例類在實例化時, 必須處理好在多個線程同時首次引用此類時的訪問限制問題,特別是當單例類作為資源控制器,在實例化時必然涉及資源初始化,而資源初始化很有可能耗費時間。這意味著出現(xiàn)多線程同時首次引用此類的機率變得較大。
      餓漢式單例類可以在Java 語言內(nèi)實現(xiàn), 但不易在C++ 內(nèi)實現(xiàn),因為靜態(tài)初始化在C++ 里沒有固定的順序,因而靜態(tài)的m_instance 變量的初始化與類的加載順序沒有保證,可能會出問題。這就是為什么GoF 在提出單例類的概念時,舉的例子是懶漢式的。他們的書影響之大,以致Java 語言中單例類的例子也大多是懶漢式的。實際上,本書認為餓漢式單例類更符合Java 語言本身的特點。
      使用單例模式必要條件:
      下面我們探討一下使用單例模式的必要條件。
      在一個系統(tǒng)要求一個類只有一個實例時才應當使用單例模式。反過來說,如果一個類可以有幾個實例共存,那么就沒有必要使用單例類。但是有經(jīng)驗的讀者可能會看到很多不當?shù)厥褂脝卫J降睦樱梢娮龅缴厦孢@一點并不容易,下面就是一些這樣的情況。
      例子一
      問:我的一個系統(tǒng)需要一些"全程"變量。學習了單例模式后,我發(fā)現(xiàn)可以使用一個單例類盛放所有的"全程"變量。請問這樣做對嗎?
      答:這樣做是違背單例模式的用意的。單例模式只應當在有真正的"單一實例"的需求時才可使用。
      一個設(shè)計得當?shù)南到y(tǒng)不應當有所謂的"全程"變量,這些變量應當放到它們所描述的實體所對應的類中去。將這些變量從它們所描述的實體類中抽出來,放到一個不相干的單例類中去,會使得這些變量產(chǎn)生錯誤的依賴關(guān)系和耦合關(guān)系。
      例子二
      問:我的一個系統(tǒng)需要管理與數(shù)據(jù)庫的連接。學習了單例模式后,我發(fā)現(xiàn)可以使用一個單例類包裝一個Connection對象,并在finalize()方法中關(guān)閉這個Connection對象。這樣的話,在這個單例類的實例沒有被人引用時,這個finalize() 對象就會被調(diào)用,因此,Connection 對象就會被釋放。這多妙啊。
      答:這樣做是不恰當?shù)摹3怯袉我粚嵗男枨螅蝗徊灰褂脝卫J健T谶@里Connection 對象可以同時有幾個實例共存,不需要是單一實例。
      單例模式有很多的錯誤使用案例都與此例子相似,它們都是試圖使用單例模式管理共享資源的生命周期,這是不恰當?shù)摹?/div>
      下面簡單說一下,筆者現(xiàn)在學習安卓,寫了一個很小的音樂播放播放器,自己寫了一個application。Application和Actovotu,Service一樣是android框架的一個系統(tǒng)組件,當android程序啟動時系統(tǒng)會創(chuàng)建一個 application對象,用來存儲系統(tǒng)的一些信息。通常我們是不需要指定一個Application的,這時系統(tǒng)會自動幫我們創(chuàng)建,如果需要創(chuàng)建自己的Application,也很簡單創(chuàng)建一個類繼承 Application并在manifest的application標簽中進行注冊(只需要給Application標簽增加個name屬性把自己的 Application的名字定入即可)
    package com.frewen.ttplayer;
    importjava.util.ArrayList;
    importjava.util.LinkedList;
    importjava.util.List;
    importandroid.app.Activity;
    importandroid.app.Application;
    importandroid.content.Context;
    importandroid.graphics.Bitmap;
    importandroid.graphics.BitmapFactory;
    importandroid.media.MediaPlayer;
    importandroid.util.Log;
    import com.frewen.ttplayer.entry.Music;
    import com.frewen.ttplayer.entry.impl.Musicdata;
    import com.frewen.ttplayer.util.MusicPreference;
    public classMyApplication extends Application {
    public static MediaPlayer mediaPlayer;
    public static MusicPreferencemusicPreference;
    public static ArrayList<Music> musics= new ArrayList<Music>();
    public static boolean isStart = false;
    public List<Activity> activityList =new LinkedList<Activity>();
    public static Bitmap bitmap_l;
    public static Bitmap bitmap_s;
    public static MyApplication instance;
    public ArrayList<Music> getMusics() {
    return musics;
    }
    public static Context context;
    @Override
    public void onCreate() {
    super.onCreate();
    context = getApplicationContext();
    new Thread(new Runnable() {
    @Override
    public void run() {
    setMusics(Musicdata.getMultiDatas(context));
    bitmap_l = BitmapFactory.decodeResource(context.getResources(),
    R.drawable.default_bg_l);
    bitmap_s =BitmapFactory.decodeResource(context.getResources(),
    R.drawable.default_bg_s);
    }
    }).start();
    mediaPlayer = new MediaPlayer();
    musicPreference = new MusicPreference(context);
    }
    public void setMusics(ArrayList<Music>ms) {
    musics.clear();
    musics = ms;
    Log.i("test", "列表長度" + this.musics.size());
    }
    public MyApplication() {
    }
    // 單例模式中獲取唯一的MyApplication實例
    public static MyApplication getInstance() {
    if (null == instance) {
    instance = new MyApplication();
    }
    return instance;
    }
    // 添加Activity到容器中
    public void addActivity(Activity activity) {
    activityList.add(activity);
    }
    // 遍歷所有Activity并finish
    public void exit() {
    for (Activity activity : activityList) {
    activity.finish();
    }
    System.exit(0);
    }
    /**
    * 向musics集合中追加一組miusic信息
    *
    *@param musics
    */
    public void append(ArrayList<Music>musics) {
    if (musics != null) {
    this.musics.addAll(musics);
    }
    }
    public void append(Music music) {
    if (music != null) {
    this.musics.add(music);
    }
    }
    }
      android系統(tǒng)會為每個程序運行時創(chuàng)建一個Application類的對象且僅創(chuàng)建一個,所以Application可以說是單例 (singleton)模式的一個類.application對象的生命周期是整個程序中最長的,它的生命周期就等于這個程序的生命周期。因為它是全局的單例的,所以在不同的Activity,Service中獲得的對象都是同一個對象。所以通過Application來進行一些,數(shù)據(jù)傳遞,數(shù)據(jù)共享等,數(shù)據(jù)緩存等操作。

    posted on 2014-04-22 18:32 順其自然EVO 閱讀(337) 評論(0)  編輯  收藏 所屬分類: 測試學習專欄

    <2014年4月>
    303112345
    6789101112
    13141516171819
    20212223242526
    27282930123
    45678910

    導航

    統(tǒng)計

    • 隨筆 - 3936
    • 文章 - 404
    • 評論 - 179
    • 引用 - 0

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 国产精品亚洲综合天堂夜夜| 一个人免费视频在线观看www | 亚洲精品无码久久| 永久免费av无码网站大全| 一级毛片在播放免费| 亚洲狠狠久久综合一区77777| 两个人的视频高清在线观看免费| 羞羞的视频在线免费观看| 久久精品夜色国产亚洲av| 午夜小视频免费观看| 免费萌白酱国产一区二区三区| 亚洲另类自拍丝袜第1页| 亚洲国产精品日韩| 每天更新的免费av片在线观看 | 四虎成年永久免费网站| 美女被吸屁股免费网站| 亚洲第一成年人网站| 亚洲人成网站色在线入口| 成人免费大片免费观看网站| 国产免费MV大全视频网站| 亚洲www在线观看| 国产亚洲综合成人91精品 | 亚洲综合亚洲综合网成人| 国产91免费视频| 91免费在线视频| 久久无码av亚洲精品色午夜 | 亚洲免费闲人蜜桃| 国产亚洲精品成人AA片新蒲金 | 永久免费av无码网站韩国毛片 | 免费福利网站在线观看| 一级特黄色毛片免费看| 学生妹亚洲一区二区| 亚洲avav天堂av在线不卡| 亚洲第一区在线观看| A级毛片内射免费视频| 日本免费人成视频在线观看| 国产精品美女久久久免费| 久久亚洲精品无码gv| 亚洲精品福利你懂| 亚洲一区精品中文字幕| 亚洲人成77777在线播放网站|