Java內功心法之設計模式學習(二)

在上一篇文章簡單的講解了設計模式的七大原則和UML類圖的使用,這篇文章開始學習23種設計模式。

1、設計模式類型

設計模式分爲三種類型,共 23 種java

1) 建立型模式:單例模式、抽象工廠模式、原型模式、建造者模式、工廠模式。數據庫

2) 結構型模式:適配器模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式、代理模式。設計模式

3) 行爲型模式:模版方法模式、命令模式、訪問者模式、迭代器模式、觀察者模式、中介者模式、備忘錄模式、解釋器模式(Interpreter 模式)、狀態模式、策略模式、職責鏈模式(責任鏈模式)。安全

注意:不一樣的書籍上對分類和名稱略有差異。session

2、單例設計模式

1.1 單例設計模式介紹

所謂類的單例設計模式,就是採起必定的方法保證在整個的軟件系統中,對某個類只能存在一個對象實例, 而且該類只提供一個取得其對象實例的方法(靜態方法)。多線程

好比 Hibernate 的 SessionFactory,它充當數據存儲源的代理,並負責建立 Session 對象。SessionFactory 並非輕量級的,通常狀況下,一個項目一般只須要一個 SessionFactory 就夠,這是就會使用到單例模式。工具

1.2 單例設計模式八種方式

單例模式有八種方式:源碼分析

1) 餓漢式(靜態常量)
2) 餓漢式(靜態代碼塊)
3) 懶漢式(線程不安全)
4) 懶漢式(線程安全,同步方法)
5) 懶漢式(線程安全,同步代碼塊)
6) 雙重檢查
7) 靜態內部類
8) 枚舉性能

1.2.1 餓漢式(靜態常量)

餓漢式(靜態常量)應用實例
步驟以下:
1) 構造器私有化 (防止 new )
2) 類的內部建立對象
3) 向外暴露一個靜態的公共方法。getInstance
4) 代碼實現學習

package com.atguigu.singleton.type1;

public class SingletonTest01 {

  public static void main(String[] args) {
    //測試
    Singleton instance = Singleton.getInstance();
    Singleton instance2 = Singleton.getInstance();    
    System.out.println(instance == instance2); // true
    System.out.println("instance.hashCode=" +  instance.hashCode()); 
    System.out.println("instance2.hashCode=" +  instance2.hashCode());
  }

}


//餓漢式(靜態變量) 
class Singleton {
  //1. 構造器私有化,  外部能 new 
  private Singleton() {}

  //2.本類內部建立對象實例
  private final static Singleton instance = new Singleton();

  //3. 提供一個公有的靜態方法,返回實例對象
  public static Singleton getInstance() { 
    return instance;
  }
}

➢ 優缺點說明:
1) 優勢:這種寫法比較簡單,就是在類裝載的時候就完成實例化。避免了線程同步問題。
2) 缺點:在類裝載的時候就完成實例化,沒有達到 Lazy Loading 的效果。若是從始至終從未使用過這個實例,則會形成內存的浪費

3) 這種方式基於 classloder 機制避免了多線程的同步問題,不過,instance 在類裝載時就實例化,在單例模式中大多數都是調用 getInstance 方法, 可是致使類裝載的緣由有不少種,所以不能肯定有其餘的方式(或者其餘的靜態方法)致使類裝載,這時候初始化 instance 就沒有達到 lazy loading 的效果

4) 結論:這種單例模式可用,可能形成內存浪費

1.2.2 懶漢式(線程不安全)

package com.atguigu.singleton.type3;


public class SingletonTest03 {
 
  public static void main(String[] args) {
    System.out.println("懶漢式 1 , 線程不安全~");
    Singleton instance = Singleton.getInstance(); 
    Singleton instance2 = Singleton.getInstance(); 
    System.out.println(instance == instance2); // true
  
    System.out.println("instance.hashCode=" +  instance.hashCode());   
     System.out.println("instance2.hashCode=" + instance2.hashCode());
  }
}


class Singleton {
  private static Singleton instance;
  private Singleton() {}

  // 提供一個靜態的公有方法,當使用到該方法時,纔去建立 instance
  // 即懶漢式
  public static Singleton getInstance() { 
  if(instance == null) {
    instance = new Singleton();
  }
  return instance;
 }
}

➢ 優缺點說明:
1) 起到了 Lazy Loading 的效果,可是隻能在單線程下使用。
2) 若是在多線程下,一個線程進入了 if (singleton == null)判斷語句塊,還將來得及往下執行,另外一個線程也經過了這個判斷語句,這時便會產生多個實例。因此在多線程環境下不可以使用這種方式
3) 結論:在實際開發中,不要使用這種方式

1.2.3 雙重檢查

package com.atguigu.singleton.type6;


public class SingletonTest06 {

  public static void main(String[] args) {
    System.out.println("雙重檢查");
    Singleton instance = Singleton.getInstance(); 
    Singleton instance2 = Singleton.getInstance(); 
    System.out.println(instance == instance2); // true
    System.out.println("instance.hashCode=" + instance.hashCode());
    
    System.out.println("instance2.hashCode=" + instance2.hashCode());
 
}

}

// 懶漢式(線程安全,同步方法) 
class Singleton {
  private static volatile Singleton instance;
  private Singleton() {}

 //提供一個靜態的公有方法,加入雙重檢查代碼,解決線程安全問題, 同時解決懶加載問題
//同時保證了效率, 推薦使用


public static synchronized Singleton getInstance() {  

   if(instance == null) {
      synchronized (Singleton.class) { 
      if(instance == null) {
         instance = new Singleton();
      }
   }
  }
   return instance;
 }
}

➢ 優缺點說明:

1) Double-Check 概念是多線程開發中常使用到的,如代碼中所示,咱們進行了兩次 if (singleton == null)檢查,這樣就能夠保證線程安全了。
2) 這樣,實例化代碼只用執行一次,後面再次訪問時,判斷 if (singleton == null),直接 return 實例化對象,也避免的反覆進行方法同步.
3) 線程安全;延遲加載;效率較高
4) 結論:在實際開發中,推薦使用這種單例設計模式

1.3 單例模式在JDK應用的源碼分析

1) 咱們 JDK 中,java.lang.Runtime 就是經典的單例模式(餓漢式)
2) 代碼分析+Debug 源碼+代碼說明

image.png

1.4 單例模式注意事項和細節說明

1) 單例模式保證了 系統內存中該類只存在一個對象,節省了系統資源,對於一些須要頻繁建立銷燬的對象,使用單例模式能夠提升系統性能
2) 當想實例化一個單例類的時候,必需要記住使用相應的獲取對象的方法,而不是使用 new

3) 單例模式使用的場景:須要頻繁的進行建立和銷燬的對象、建立對象時耗時過多或耗費資源過多(即:重量級對象),但又常常用到的對象、工具類對象、頻繁訪問數據庫或文件的對象(好比數據源、session 工廠等)

相關文章
相關標籤/搜索