3.[研磨設計模式筆記]單例模式
1.定義
保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。
2.解決問題
——讀取配置檔案的內容
不用模式的解決方案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
public class AppConfig {
private String parameterA;
private String parameterB;
public String getParameterA() {
return parameterA;
}
public String getParameterB() {
return parameterB;
}
public AppConfig() {
readConfig();
}
private void readConfig() {
Properties p = new Properties();
InputStream in = null ;
try {
in = AppConfig. class .getResourceAsStream(
“AppConfig.properties”);
p.load(in);
this .paramterA = p.getProperty(“paramA”);
this .paramterB = p.getProperty(“paramB”);
} catch (Exception e) {
} finally {
try {
in.close();
} catch (Exception e) {
}
}
}
} public class Client {
public static void main(String[] args) {
AppConfig Config = new AppConfig();
String paramA = config.getParameterA();
String paramB = config.getParameterB();
}
} |
使用單例模式來解決問題
(餓漢式)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
public class AppConfig {
private static AppConfig instance = new AppConfig();
public static AppConfig() getInstance() {
return instance;
}
private String parameterA;
private String parameterB;
public String getParameterA() {
return parameterA;
}
public String getParameterB() {
return parameterB;
}
private AppConfig() {
readConfig();
}
private void readConfig() {
Properties p = new Properties();
InputStream in = null ;
try {
in = AppConfig. class .getResourceAsStream(
“AppConfig.properties”);
p.load(in);
this .paramterA = p.getProperty(“paramA”);
this .paramterB = p.getProperty(“paramB”);
} catch (Exception e) {
} finally {
try {
in.close();
} catch (Exception e) {
}
}
}
} public class Client {
public static void main(String[] args) {
AppConfig Config = AppConfig.getInstance();
String paramA = config.getParameterA();
String paramB = config.getParameterB();
}
} |
3.模式講解
在不用模式的解決方案中,客戶端是通過new一個AppConfig的例項來得到一個操作配置檔案內容的物件。如果在系統執行中,有很多地方都需要使用配置檔案的內容,也就會有很多地方都建立AppConfig物件的例項。這樣系統會同時存在多份配置檔案的內容,會嚴重浪費記憶體資源。
解決思路
分析上面的問題,一個類能夠/被建立多個例項,問題在於/類的構造方法是公開的,也就是可以/讓類的外部/通過構造方法建立多個例項。要控制一個類/只被建立一個例項,那就是把類的建構函式/私有化,然後由這個類來/提供外部訪問/類例項的方法,這就是單例模式的實現方式。
單例模式使用來保證這個類在執行期間只會被建立一個類例項,另外,單例模式還提供一個全域性唯一訪問這個類例項的訪問點,就是getInstance方法。
示例程式碼
(懶漢式)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class Singleton {
//4:定義一個變數來儲存建立好的類例項
//5:因為這個變數要在靜態方法中使用,所以需要加上static修飾
private static Singleton instance = null ;
//1:私有化構造方法,好在內部控制建立例項的數目
private Singleton() {}
//2:定義一個方法來為客戶端提供類例項
//3:這個方法需要定義成類方法(靜態方法),也就是要加static
public static synchronized Singleton getInstance() {
//6:判斷儲存例項的變數是否有值
if (instance == null ) {
//6.1:如果沒有,就建立一個類例項,並把賦值給儲存例項的變數
instance = new Singleton();
}
//6.2:如果有值,那就直接使用
return instance;
}
} |
(餓漢式)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/** * Java中 static 的特性:
* 1 . static 變數在類載入的時候進行初始化。
* 2 .多個例項的 static 變數會共享同一塊記憶體區域。
* 在Java中 static 變數只會被初始化一次,就是在類載入的時候,而且多個例項都會共享這個記憶體空間。
/* public class Singleton {
//4:定義一個變數來儲存建立好的類例項
//直接在這裡建立類例項,只能建立一次
private static Singleton instance = new Singleton();
//1:私有化構造方法,好在內部控制建立例項的數目
private Singleton() {}
//2:定義一個方法來為客戶端提供類例項
//3:這個方法需要定義成類方法(靜態方法),也就是要加static
public static Singleton getInstance() {
//5:直接使用以建立好的例項
return instance;
}
} |
在懶漢式方案裡,強制加上static,並沒有使用static的特性;而在餓漢式方案裡,是主動加上static,使用了static的特性。
單例模式的懶漢式實現體現了延遲載入的思想,即就是一開始不要載入資源或資料,一直等,等到要使用這個資源或資料才載入,也成Lazy Load。
單例模式的懶漢式實現還體現了快取的思想,即當某些資源或資料被頻繁地使用,而這些資源或資料儲存在系統外部(如資料庫、硬碟檔案等),每次操作這些資料的時候都要去獲取。通過把這些資料快取到記憶體中,每次操作先到記憶體裡面找,如果有就直接使用,如果沒有就去獲取,並設定到快取中,下一次訪問的時候就可以直接從記憶體中獲取。
應用範圍
Java裡面實現單例的是一個虛擬機器範圍,虛擬機器在通過自己的ClassLoader裝載餓漢式實現單例類就會建立一個類的例項。
單例模式呼叫示意圖
(懶漢式)
(餓漢式)
單例模式的優缺點
1.時間和空間
懶漢式是典型的時間換空間;
餓漢式是典型的空間換時間。
2.執行緒安全
不加同步的懶漢式是執行緒不安全的;
餓漢式是執行緒安全的。
雙重檢查加鎖
指的是:並不是每次進入getInstance方法都需要同步,而是先不同步,進入方法後,先檢查例項是否存在,如果不存在,就在同步的情況下建立一個例項,這是第二重檢查。這樣,就只需要同步一次,從而減少多次在同步情況下進行判斷浪費的時間。
雙重檢查加鎖的實現使用了一個關鍵字volatile,意思是:被volatile修飾的變數的值,將不會被本地執行緒快取,所有對該變數的讀寫都是直接操作共享記憶體的,從而確保多個執行緒能正確的處理該變數。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class Singleton {
//對儲存例項的變數增加volatile的修飾
private volatile static Singleton instance = null ;
private Singleton() {}
public static Singleton getInstance() {
//先檢查例項是否存在,如果不存在才進入下面的同步塊
if (instance == null ) {
//同步塊,執行緒安全地建立例項
synchronized (Singleton. class ) {
//再次檢查例項是否存在,如果不存在才真正地建立例項
if (instance == null ) {
instance = new Singleton();
}
}
}
return instance;
}
} |
4.思考
單例模式的本質:控制例項數目
何時選用單例模式:
如果當:需要控制一個類例項只能有一個,且客戶只能從一個全域性訪問點控制它時,選用單例模式。
相關文章
- 設計模式學習筆記——單例模式設計模式筆記單例
- 設計模式學習筆記之單例模式設計模式筆記單例
- Java設計模式學習筆記(五) 單例模式Java設計模式筆記單例
- 設計模式之“物件效能模式”: Singleton 單例模式(筆記)設計模式物件單例筆記
- 大話設計模式讀書筆記3——單例模式設計模式筆記單例
- Head First 設計模式筆記 3.裝飾者模式設計模式筆記
- java/android 設計模式學習筆記(1)--- 單例模式JavaAndroid設計模式筆記單例
- [設計模式]單例設計模式設計模式單例
- 設計模式-單例模式設計模式單例
- [設計模式] 單例模式設計模式單例
- 設計模式 —— 單例模式設計模式單例
- 設計模式(單例模式)設計模式單例
- 設計模式——單例模式設計模式單例
- 設計模式--單例模式設計模式單例
- 設計模式 單例模式設計模式單例
- 設計模式之單例模式(《JavaScript設計模式與開發實踐》讀書筆記)設計模式單例JavaScript筆記
- 設計模式-單例模式、多例模式設計模式單例
- 設計模式之單例設計模式設計模式單例
- 設計模式一(單例模式)設計模式單例
- 設計模式之☞單例模式設計模式單例
- Java設計模式–單例模式Java設計模式單例
- Java設計模式——單例模式Java設計模式單例
- Java設計模式--單例模式Java設計模式單例
- js設計模式--單例模式JS設計模式單例
- Java設計模式 | 單例模式Java設計模式單例
- 設計模式之單例模式設計模式單例
- Java設計模式【單例模式】Java設計模式單例
- 設計模式之---單例模式設計模式單例
- 設計模式(二)——單例模式設計模式單例
- PHP設計模式_單例模式PHP設計模式單例
- 設計模式系列-單例模式設計模式單例
- 設計模式(一)_單例模式設計模式單例
- 設計模式1——單例模式設計模式單例
- 設計模式(七):單例模式設計模式單例
- PHP設計模式——單例模式PHP設計模式單例
- 設計模式—單例模式(轉)設計模式單例
- 常用設計模式-單例模式設計模式單例
- Java設計模式-單例模式Java設計模式單例