java 單態模式

核心--在類的內部把構造器私有化,同時在內部產生對象,並通過類.靜態方法(static)返回實例化對象的引用


設計模式是在大量的實踐總結和理論化之後優選的代碼結果,編程風格,以及解決問題的思考方式.設計模式就像是經典的棋譜,不同的棋局我們用不同的棋譜.

單態設計模式:採取一定的方法保證在整個軟件系統中,對某個類只能產生一個對象實例,並且該類只提供一個取得其對象的實例方法.

在java中實現單態模式只需要執行以下三步:  

  1.將類的構造方法的訪問權限聲明爲private.這樣就不能用new操作符在類的外部產生類的對象了,但在類內部仍可以產生該類的對象.

  2.在類內部生成一個靜態的實例.

  3.提供一個靜態的方法用於外部取得該類的實例.

  因爲在類的外部無法得到類的對象,所以只能調用該類的某個靜態方法以返回類內部創建的對象,又因爲靜態方法只能訪問類中的靜態成員變量,所以,指向類內部產生該類對象的變量也必須定義成靜態的.


 


class Chinese{

    static Chinese objRef = new Chinese();

   

    private Chinese(){}

    public static Chinese getInstance(){

        return objRef;

    }

}

 

class Chinese_opt{

    static Chinese_opt objRef = null;

    private Chinese_opt(){}

    public static Chinese_opt getInstance(){

        if(objRef == null)

            objRef = new Chinese_opt();

        return objRef;

    }

   

}

class TestChinese{

    public static void main(String[] args){

        Chinese chinese1 = Chinese.getInstance();

        Chinese chinese2 = Chinese.getInstance();

        System.out.println(chinese1 == chinese2);

    }

}





 

1:構造方法私有化:

面向對象編程的三大特性:封裝、繼承、多態。類的封裝性不僅體現在對屬性的封裝上,實際上方法也是可以被封裝的,構造方法是特殊的方法當然也可以被封裝,例如下面的代碼就是對構造方法的封裝:

package com.zxf.javaopp;

 

public class Singleton {

    private Singleton(){     // 將構造方法進行了封裝,私有化  

    }

    public void print(){

       System.out.println("Hello World!!!") ;

    }

}

構造函數被私有化,不能在外部實例化,就無法在外部使用,此時只能在該類的內部實例化對象了,然後將該類拿到外部進行使用,由於該類不能再外部實例化,此時在內部的實例化必須是用static關鍵字修飾的:代碼如下:

package com.zxf.javaopp;

 

class Singleton1{

    static Singleton1 instance = new Singleton1() ;  // 在內部產生本類的實例化對象

    private Singleton1(){       // 將構造方法進行了封裝,私有化  

    }

    public void print(){

       System.out.println("Hello World!!!") ;

    }

}

public class SingletonDemo01{

    public static void main(String args[]){

       Singleton1 s1 = null ;   // 聲明對象

       s1 = Singleton1.instance ;  // 取得實例化對象

       s1.print() ;      // 調用方法

    }

}

雖然上面的代碼實現了功能,但又有些問題:通常情況下:我們將屬性封裝,此時的代碼就要修改如下:

package com.zxf.javaopp;

 

class Singleton1{

    static Singleton1 instance = new Singleton1() ;  // 在內部產生本類的實例化對象

    public static Singleton1 getInstance(){       // 通過靜態方法取得instance對象

       return instance ;

    }

    private Singleton1(){       // 將構造方法進行了封裝,私有化  

    }

    public void print(){

       System.out.println("Hello World!!!") ;

    }

}

public class SingletonDemo01{

    public static void main(String args[]){

       Singleton1 s1 = null ;   // 聲明對象

       s1 = Singleton1.getInstance() ; // 取得實例化對象

       s1.print() ;      // 調用方法

    }

}

以上的代碼似乎變得很複雜,不如不將構造方法實例化呢,但是爲什麼又會這樣做呢?

假如我們現在要產生幾個對象:按以往的代碼,就需要實例化多次,每個對象都有其對應的堆棧空間,此時的內存就消耗的很多,系統的效率坑定比較低,但是使用將構造方法封裝的模式效率就比較高:

JAVA單態設計模式

 使用將構造方法封裝的方法:無論產生多少個對象,我們只實例化一次,這樣的設計在設計模式上稱爲單態設計模式(單例設計模式):

singleton,如果不希望一個類產生多個實例的話,則必須使用單態設計模式,此設計模式,在以後的高性能開發中經常使用,而且在java的類庫中大量的使用了此設計模式。

    所謂單態就是在入口處限制了對象的實例操作。

    單態設計模式的意義:

實際上這種模式非常常用,我們大家使用的windows操作系統中就使用了此設計模式,windows中用一個回車站: ,除了桌面以外,其他的每個硬盤中都有一個回車站,其他的回車站和其他硬盤的每個回車站都是同一個,也就是所整個操作系統中有且只有一個回車站,各個地方只是引用此實例。

總結:

單態設計模式的核心就是將類的

 構造函數私有化,在類的內部產生實例對象,並通過類的靜態方法返回類的實例對象。


============================================================================================

 單例設計模式

Singleton是一種創建型模式,指某個類採用Singleton模式,則在這個類被創建後,只可能產生一個實例供外部訪問,並且提供一個全局的訪問點。

核心知識點如下:

(1) 將採用單例設計模式的類的構造方法私有化(採用private修飾)。

(2) 在其內部產生該類的實例化對象,並將其封裝成private static類型。

(3) 定義一個靜態方法返回該類的實例。

複製代碼
/** 
 * 方法一
 * 單例模式的實現:餓漢式,線程安全 但效率比較低 
 */  
public class SingletonTest {  

    // 定義一個私有的構造方法
    private SingletonTest() {  
    }  

    // 將自身的實例對象設置爲一個屬性,並加上Static和final修飾符
    private static final SingletonTest instance = new SingletonTest();  

    // 靜態方法返回該類的實例
    public static SingletonTest getInstancei() {  
        return instance;  
    }  
  
}
複製代碼

方法一就是傳說的中的餓漢模式
優點是:寫起來比較簡單,而且不存在多線程同步問題,避免了synchronized所造成的性能問題;
缺點是:當類SingletonTest被加載的時候,會初始化static的instance,靜態變量被創建並分配內存空間,從這以後,這個static的instance對象便一直佔着這段內存(即便你還沒有用到這個實例),當類被卸載時,靜態變量被摧毀,並釋放所佔有的內存,因此在某些特定條件下會耗費內存。

複製代碼
/**  
 *方法二
 * 單例模式的實現:飽漢式,非線程安全   
 *   
 */  
public class SingletonTest {

    // 定義私有構造方法(防止通過 new SingletonTest()去實例化)
    private SingletonTest() {   
    }   

    // 定義一個SingletonTest類型的變量(不初始化,注意這裏沒有使用final關鍵字)
    private static SingletonTest instance;   

    // 定義一個靜態的方法(調用時再初始化SingletonTest,但是多線程訪問時,可能造成重複初始化問題)
    public static SingletonTest getInstance() {   
        if (instance == null)   
            instance = new SingletonTest();   
        return instance;   
    }   
} 
複製代碼

方法二就是傳說的中的飽漢模式
優點是:寫起來比較簡單,當類SingletonTest被加載的時候,靜態變量static的instance未被創建並分配內存空間,當getInstance方法第一次被調用時,初始化instance變量,並分配內存,因此在某些特定條件下會節約了內存;
缺點是:併發環境下很可能出現多個SingletonTest實例。

複製代碼
/**  
 *方法三
 * 單例模式的實現:飽漢式,線程安全簡單實現   
 *   
 */  
public class SingletonTest {

    // 定義私有構造方法(防止通過 new SingletonTest()去實例化)
    private SingletonTest() {   
    }   

    // 定義一個SingletonTest類型的變量(不初始化,注意這裏沒有使用final關鍵字)
    private static SingletonTest instance;   

    // 定義一個靜態的方法(調用時再初始化SingletonTest,使用synchronized 避免多線程訪問時,可能造成重的復初始化問題)
    public static synchronized  SingletonTest getInstance() {   
        if (instance == null)   
            instance = new SingletonTest();   
        return instance;   
    }   
} 
複製代碼

方法三爲方法二的簡單優化
優點是:使用synchronized關鍵字避免多線程訪問時,出現多個SingletonTest實例。
缺點是:同步方法頻繁調用時,效率略低。

複製代碼
/**  
 * 方法四
 * 單例模式最優方案
 * 線程安全  並且效率高  
 *  
 */  
public class SingletonTest { 

    // 定義一個私有構造方法
    private SingletonTest() { 
     
    }   
    //定義一個靜態私有變量(不初始化,不使用final關鍵字,使用volatile保證了多線程訪問時instance變量的可見性,避免了instance初始化時其他變量屬性還沒賦值完時,被另外線程調用)
    private static volatile SingletonTest instance;  

    //定義一個共有的靜態方法,返回該類型實例
    public static SingletonTest getIstance() { 
        // 對象實例化時與否判斷(不使用同步代碼塊,instance不等於null時,直接返回對象,提高運行效率)
        if (instance == null) {
            //同步代碼塊(對象未初始化時,使用同步代碼塊,保證多線程訪問時對象在第一次創建後,不再重複被創建)
            synchronized (SingletonTest.class) {
                //未初始化,則初始instance變量
                if (instance == null) {
                    instance = new SingletonTest();   
                }   
            }   
        }   
        return instance;   
    }   
}
複製代碼

方法四爲單例模式的最佳實現。內存佔用地,效率高,線程安全,多線程操作原子性。

 

(事實上,可以通過Java反射機制來實例化private類型的構造方法,此時基本上會使所有的Java單例實現失效。本帖不討論反射情況下問題,默認無反射,也是常見的面試已經應用場景)

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章