創建型模式:單態

單態模式可能是23種創建模式種最簡單和容易理解的,創建型模式是主要是爲了解決對象的創建的方式,單態則是爲了保證創建的對象的唯一性。

模式場景與說明

有早期編碼經驗的開發者一般在N層應用開發中的業務邏輯層和持久層之間會有數據庫連接的獲取,不管是從緩衝池中獲取還是直接連接JDBC,爲了避免創建多個示例產生資源的浪費,一般會使用單態模式對創建對象進行控制。實際上除此之外,在類似的池化控制中都可以類似的引入,比如線程池等。此類對象創建一般存在:重(類似數據庫連接的獲取)、頻(使用程度較爲頻繁)的特點。

實現方式1

單態模式實現非常簡單,一般只要把握兩個要點,就能快速創建一個單態模式的類:

  • 控制構造函數:私有化構造函數保證無法隨意創建對象
  • 統一創建對象:在類中提供對象的構建方法並提供公有方法返回創建的實例(一般爲靜態函數)

在這裏插入圖片描述

實現示例

最簡單的示例代碼如下所示

public class Singleton {
    // use private key word to avoid being used directly
    private Singleton() {}
    private static Singleton instance = new Singleton();

    // use public method to get singleton instance
    public static Singleton getInstance(){
        return instance;
    }
}

調用方式:Singleton.getInstance();

這裏稍微修改一下,顯示一下輸出內容,特意在構建函數裏添加sleep,可以在多個終端同時啓動,可以驗證並行時仍然使用同一個實例(hashcode相同)。

package com.liumiao;
import java.time.LocalDateTime;

public class Singleton {

    // use private key word to avoid being used directly
    private Singleton() {
        System.out.printf("%s: Single instance creating begins... \n" ,LocalDateTime.now());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s: Single instance creating ends... \n" ,LocalDateTime.now());
    }
    private static Singleton instance = new Singleton();

    // use public method to get singleton instance
    public static Singleton getInstance(){
        System.out.println("get Singleton instance: " + LocalDateTime.now());
        System.out.println(instance.hashCode());
        return instance;
    }
}

測試代碼如下

package com.liumiao;

public class TestSingleton extends Thread {
    public void run() {
        Singleton.getInstance();
    }
    public static void main( String[] args )
    {
        TestSingleton thread1 = new TestSingleton ();
        TestSingleton thread2 = new TestSingleton ();

        thread1.start();
        thread2.start();
    }
}

執行結果如下

2020-06-26T05:37:58.555119: Single instance creating begins... 
2020-06-26T05:37:59.583467: Single instance creating ends... 
get Singleton instance: 2020-06-26T05:37:59.583739
140350290
get Singleton instance: 2020-06-26T05:37:59.583756
140350290

實現方式2

由於實現方式1中對於實例的構建在類裝載的時候就已經完成,雖然解決了線程的同步,但是即使沒有使用到這個實例也會加載,這裏修改一下將new的動作移到getInstance中,通過是否爲空來判斷一下是否需要new進行構建對象,示例代碼如下所示:

package com.liumiao;
import java.time.LocalDateTime;

public class Singleton {

    // use private key word to avoid being used directly
    private Singleton() {
        System.out.printf("%s: Single instance creating begins... \n" ,LocalDateTime.now());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s: Single instance creating ends... \n" ,LocalDateTime.now());
    }
    private static Singleton instance = null;

    // use public method to get singleton instance
    public static Singleton getInstance(){
        System.out.println("get Singleton instance: " + LocalDateTime.now());
        if (null == instance) {
            instance = new Singleton();
        }
        System.out.println(instance.hashCode());
        return instance;
    }
}

使用同樣的測試代碼,執行結果如下,所示

get Singleton instance: 2020-06-26T05:39:00.137037
get Singleton instance: 2020-06-26T05:39:00.137051
2020-06-26T05:39:00.137567: Single instance creating begins... 
2020-06-26T05:39:00.137614: Single instance creating begins... 
2020-06-26T05:39:01.162630: Single instance creating ends... 
140350290
2020-06-26T05:39:01.162630: Single instance creating ends... 
1253458049

可以看到,單態出現了問題,產生了不同的實例(hashcode不同),因爲沒有考慮到線程安全的問題

實現方式3

這裏簡單地使用synchronized來稍作修改, 代碼如下

package com.liumiao;
import java.time.LocalDateTime;

public class Singleton {

    // use private key word to avoid being used directly
    private Singleton() {
        System.out.printf("%s: Single instance creating begins... \n" ,LocalDateTime.now());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s: Single instance creating ends... \n" ,LocalDateTime.now());
    }
    private static Singleton instance = null;

    // use public method to get singleton instance
    public static synchronized Singleton getInstance(){
        System.out.println("get Singleton instance: " + LocalDateTime.now());
        if (null == instance) {
            instance = new Singleton();
        }
        System.out.println(instance.hashCode());
        return instance;
    }
}

使用同樣的測試代碼執行結果如下

get Singleton instance: 2020-06-26T05:42:13.732276
2020-06-26T05:42:13.732766: Single instance creating begins... 
2020-06-26T05:42:14.758235: Single instance creating ends... 
346203776
get Singleton instance: 2020-06-26T05:42:14.758679
346203776

所以可以看到已經返回了相同的實例了

其他設計模式

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