weidagang2046的專欄

          物格而后知致
          隨筆 - 8, 文章 - 409, 評論 - 101, 引用 - 0
          數(shù)據(jù)加載中……

          在Java中應(yīng)用設(shè)計(jì)模式--Singleton

          本文介紹了設(shè)計(jì)模式中 Singleton 的基本概念,對其功能和用途進(jìn)行了簡單的分析,列出了通常實(shí)現(xiàn) Singleton 的幾種方法,并給出了詳細(xì)的Java 代碼.

            基本概念

            Singleton 是一種創(chuàng)建性模型,它用來確保只產(chǎn)生一個實(shí)例,并提供一個訪問它的全局訪問點(diǎn).對一些類來說,保證只有一個實(shí)例是很重要的,比如有的時(shí)候,數(shù)據(jù)庫連接或 Socket 連接要受到一定的限制,必須保持同一時(shí)間只能有一個連接的存在.再舉個例子,集合中的 set 中不能包含重復(fù)的元素,添加到set里的對象必須是唯一的,如果重復(fù)的值添加到 set,它只接受一個實(shí)例.JDK中正式運(yùn)用了Singleton模式來實(shí)現(xiàn) set 的這一特性,大家可以查看java.util.Collections里的內(nèi)部靜態(tài)類SingletonSet的原代碼.其實(shí)Singleton是最簡單但也是應(yīng)用最廣泛的模式之一,在 JDK 中隨處可見.

            簡單分析

            為了實(shí)現(xiàn) Singleton 模式,我們需要的是一個靜態(tài)的變量,能夠在不創(chuàng)建對象的情況下記憶是否已經(jīng)產(chǎn)生過實(shí)例了.靜態(tài)變量或靜態(tài)方法都可以在不產(chǎn)生具體實(shí)例的情況下直接調(diào)用,這樣的變量或方法不會因?yàn)轭惖膶?shí)例化而有所改變.在圖1的結(jié)構(gòu)中可以看到,uniqueInstance 就是這個獨(dú)立的靜態(tài)變量,它可以記憶對象是否已經(jīng)實(shí)例化了,在靜態(tài)方法 Instance 中對這個變量進(jìn)行判斷,若沒有實(shí)例化過就產(chǎn)生一個新的對象,如果已經(jīng)實(shí)例化了則不再產(chǎn)生新的對象,仍然返回以前產(chǎn)生的實(shí)例.


          圖1: Singleton 模式結(jié)構(gòu)

            具體實(shí)施

            實(shí)現(xiàn) Singleton 模式的辦法通常有三種.

            一. 用靜態(tài)方法實(shí)現(xiàn) Singleton

            這種方法是使用靜態(tài)方法來監(jiān)視實(shí)例的創(chuàng)建.為了防止創(chuàng)建一個以上的實(shí)例,我們最好把構(gòu)造器聲明為 private.

            這樣可以防止客戶程序員通過除由我們提供的方法之外的任意方式來創(chuàng)建一個實(shí)例,如果不把構(gòu)造器聲明為private,編譯器就會自作聰明的自動同步一個默認(rèn)的friendly構(gòu)造器.這種實(shí)現(xiàn)方法是最常見的,也就是圖1中結(jié)構(gòu)的標(biāo)準(zhǔn)實(shí)現(xiàn).

                  public class Singleton {
                      private static Singleton s; 
                      private Singleton(){};
                  /**
                       * Class method to access the singleton instance of the class.
                   */
                  public static Singleton getInstance() {
                   if (s == null)
                      s = new Singleton();
                    return s;
                  }
          }

          // 測試類
          class singletonTest {
            public static void main(String[] args) {
              Singleton s1 = Singleton.getInstance();
              Singleton s2 = Singleton.getInstance();
              if (s1==s2)
                System.out.println("s1 is the same instance with s2");
              else
                System.out.println("s1 is not the same instance with s2");
            }
          }

            singletonTest運(yùn)行結(jié)果是:
            s1 is the same instance with s2
            這證明我們只創(chuàng)建了一個實(shí)例.

            二. 以靜態(tài)變量為標(biāo)志實(shí)現(xiàn) Singleton

            在類中嵌入一個靜態(tài)變量做為標(biāo)志,每次都在進(jìn)入構(gòu)造器的時(shí)候進(jìn)行檢查.

            問題在于構(gòu)造器沒有返回類型,如果確定創(chuàng)建一個實(shí)例成功與否.一個方法是調(diào)用一個函數(shù)來檢查創(chuàng)建是否成功,然后簡單的返回一個來自靜態(tài)變量的值,但是這樣做是不優(yōu)雅的,而且容易發(fā)生錯誤.比較好的做法是創(chuàng)建一個當(dāng)創(chuàng)建了一個以上的實(shí)例時(shí)可以拋出異常的類,這個類僅僅是調(diào)用父類方法,好處是用了自己命名的異常類型,錯誤信息更加清晰:

          class SingletonException extends RuntimeException {
            public SingletonException(String s) {
              super(s);
            }
          }

          class Singleton {
            static boolean instance_flag = false; // true if 1 instance
            public Singleton() {
              if (instance_flag)
                throw new SingletonException("Only one instance allowed");
              else
                instance_flag = true; // set flag for 1 instance
            }
          }

          // 測試類

          public class singletonTest {
            static public void main(String argv[]) {
              Singleton s1, s2;
              // create one incetance--this should always work
              System.out.println("Creating one instance");
              try {
                s1 = new Singleton();
              } catch (SingletonException e) {
                System.out.println(e.getMessage());
              }
              // try to create another spooler --should fail
              System.out.println("Creating two instance");
              try {
                s2 = new Singleton();
              } catch (SingletonException e) {
                System.out.println(e.getMessage());
              }
            }
          }

            singletonTest運(yùn)行結(jié)果是:
            Creating one instance
            Creating two instance
            Only one instance allowed
            可以看出,第一個實(shí)例順利創(chuàng)建,第二個實(shí)例創(chuàng)建實(shí)拋出了我們自定義的異常.

            三. 用注冊器機(jī)制來創(chuàng)建 Singleton

            首先用集合中的Hashtable 和Enumeration來實(shí)現(xiàn)addItem(Object key, Object value),getItem(Object key), ,removeItem(Object key)等方法實(shí)現(xiàn)一個管理器,將key和value一一關(guān)聯(lián)起來,客戶程序員創(chuàng)建實(shí)例前首先用addItem方法進(jìn)行注冊,再用getItem方法獲取實(shí)例.Hashtable中的key是唯一的,從而保證創(chuàng)建的實(shí)例是唯一的,具體實(shí)現(xiàn)限于篇幅不再細(xì)說,在Prototype模型的應(yīng)用一文中我將會給出一個實(shí)現(xiàn)注冊器的代碼.用注冊器機(jī)制來創(chuàng)建 Singleton模式的好處是易于管理,可以同時(shí)控制多個不同類型的Singleton 實(shí)例.

            小結(jié)

            1. Singleton模式可以方便的進(jìn)行擴(kuò)充,產(chǎn)生指定數(shù)目的實(shí)例. 

            2. 在The Design Patterns Java Companion 一書中曾提到過用靜態(tài)類的方式來實(shí)現(xiàn) Singleton模式,并指出java.lang.Math就是一個例子,這里我并不表示贊同,因?yàn)镸ath并不是一個真正的對象,我們只是直接調(diào)用Math類所包裝的靜態(tài)方法而已,根本就沒有創(chuàng)建實(shí)例的過程,又從何說起只產(chǎn)生一個實(shí)例呢?這個問題我曾到Javaranch的論壇上發(fā)過帖子,所有回帖的人也都是對這一觀點(diǎn)持否定態(tài)度. 

            3. 在多線程的程序中,singleton可能會變的不可靠,可能會出現(xiàn)多個實(shí)例,解決的辦法很簡單,加個同步修飾符: public static synchronized Singleton getInstance(). 這樣就保證了線程的安全性. 

            4. 最后要說的是大家可能會看見一些其他實(shí)現(xiàn)Singleton模式的方法,因?yàn)槟J皆诰唧w的應(yīng)用時(shí)是靈活的,不是一成不變的,并沒有一個固定的做法,但大都是上面幾種方法的變形. 

          轉(zhuǎn)自:http://www.javaresearch.org/article/showarticle.jsp?column=31&thread=28424

          posted on 2005-05-26 21:54 weidagang2046 閱讀(155) 評論(0)  編輯  收藏 所屬分類: Java

          主站蜘蛛池模板: 定州市| 蚌埠市| 万全县| 潜山县| 静安区| 教育| 深水埗区| 偏关县| 双柏县| 汶上县| 玉环县| 浮山县| 南岸区| 鲜城| 大石桥市| 宜章县| 镇坪县| 安庆市| 石渠县| 汽车| 友谊县| 衡阳县| 板桥市| 安图县| 吉林市| 新沂市| 漳州市| 南康市| 兴安盟| 隆林| 云林县| 台东市| 六枝特区| 普定县| 竹溪县| 婺源县| 屯留县| 额敏县| 绥宁县| 萨迦县| 杭锦旗|