### java中有23種設計模式
#### 單例設計模式
- 概念
類的單態設計模式,就是采取一定的方法保證在整個的軟件系統中,對某個類只能存在一個對象實例,并且該類只提供一個取得其對象實例的方法。
- 解決的問題:
就是可以保證一個類在內存中的對象唯一性。(堆內存中只有一個對象)
比如:多程序讀取一個配置文件時,建議配置文件封裝成對象。會方便操作其中數據,又要保證多個程序讀到的是同一個配置文件對象,就需要該配置文件對象在內存中是唯一的。
- Runtime()方法就是單例設計模式進行設計的。
- 如何保證對象唯一性呢?
- 思想:
1,不讓其他程序創建該類對象。
2,在本類中創建一個本類對象。
3,對外提供方法,讓其他程序獲取這個對象。
- 步驟:
1,因為創建對象都需要構造函數初始化,只要將本類中的構造函數私有化,其他程序就無法再創建該類對象;
2,就在類中創建一個本類的對象;
3,定義一個方法,返回該對象,讓其他程序可以通過方法就得到本類對象。(作用:可控)
- 代碼體現:
1,私有化構造函數;
2,創建私有并靜態的本類對象;
3,定義公有并靜態的方法,返回該對象。
#### 餓漢式 直接將對象定義出來
- 示例
~~~
class Single{
//一、私有化構造方法
private Single(){}
//二、創建私有并靜態的本類對象;
private static Single s = new Single();//類已加載,對象就已經存在了
//三、定義公有并靜態的方法,返回該對象。
public static Single getInstance(){
return s ;
}
}
class SingleDemo{
public static void main(String[] args){
Single s1 = Single.getInstance();
Single s2 = Single. getInstance();
System.out.println(s1 == s2);
}
}
~~~
- 輸出結果
~~~
true
~~~
- PS
之所以不用Single.s;的方式獲取Single對象,而采用getInstance獲取是因為在getInstance方法中我們可以做一些判斷來決定是否返回Single的對象,也就是實現了對單例對象的可控。所以,給Single的構造方法加上了private限制,禁止使用者直接采用Single.s;的方式獲取。
- 注意:static修飾,隨著類的加載而加載,會損耗性能,但方法相對簡單,開發時,常用餓漢式,但是面試時,懶漢式的提問較多
#### 懶漢式
- 懶漢式:延遲加載方式。只給出變量,并不將其初始化;
- 示例
~~~
class Single{
//類加載進來,沒有對象,只有調用了getInstance方法時,才會創建對象
//延遲加載形式
private static Single s = null;
private Single(){}
public static Single getInstance(){
if(s == null)
s = new Single();
return s ;
}
}
class SingleDemo{
public static void main(String[] args){
Single s1 = Single. getInstance();
Single s2 = Single. getInstance();
System.out.println(s1 == s2);
}
}
~~~
- 運行結果
~~~
true
~~~
- 延遲加載方式,類加載進來,沒有對象,只有調用了getInstance方法時,才會創建對象;只給出變量,并不將其初始化,第一次用的時候相對較慢,因為需要加載;線程不安全,有可能保證不了對象的唯一性。
- 總結:
餓漢式:static修飾,隨著類的加載而加載,會損耗性能,但是方法相對簡單
懶漢式 :第一次用的時候相對較慢,因為需要加載!線程,不安全!
[Android開發設計模式之——單例模式 ](http://blog.csdn.net/beyond0525/article/details/22794221)
單例模式是設計模式中最常見也最簡單的一種設計模式,保證了在程序中只有一個實例存在并且能全局的訪問到。比如在Android實際APP 開發中用到的 賬號信息對象管理, 數據庫對象(SQLiteOpenHelper)等都會用到單例模式。
- 一、作用
單例模式(Singleton):保證一個類僅有一個實例,并提供一個訪問它的全局訪問點
- 二、適用場景
1. 應用中某個實例對象需要頻繁的被訪問。
2. 應用中每次啟動只會存在一個實例。如賬號系統,數據庫系統。
- 三、常用的使用方式
(1)懶漢式
這是在開發中很容易就能寫出來的一種方式,如下
~~~
public class Singleton {
/* 持有私有靜態實例,防止被引用,此處賦值為null,目的是實現延遲加載 */
private static Singleton instance = null;
/* 私有構造方法,防止被實例化 */
private Singleton() {
}
/* 1:懶漢式,靜態工程方法,創建實例 */
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
~~~
調用:`Singleton.getInstance().method();`
優點:延遲加載(需要的時候才去加載)
缺點: 線程不安全,在多線程中很容易出現不同步的情況,如在數據庫對象進行的頻繁讀寫操作時。
(2)加同步鎖
既然線程不安全,那就加上同步鎖,一種加法如下:
~~~
/*2.懶漢式變種,解決線程安全問題**/
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
~~~
更一般的寫法是這樣
~~~
/*加上synchronized,但是每次調用實例時都會加載**/
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
return instance;
}
~~~
調用:`Singleton.getInstance().method(); `
優點:解決了線程不安全的問題。
缺點:效率有點低,每次調用實例都要判斷同步鎖
補充:在android源碼中使用的該單例方法有:InputMethodManager,AccessibilityManager等都是使用這種單例模式
(3)雙重檢驗鎖
要優化(2)中因為每次調用實例都要判斷同步鎖的問題,很多人都使用下面的一種雙重判斷校驗的辦法
~~~
/*3.雙重鎖定:只在第一次初始化的時候加上同步鎖*/
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
~~~
這種方法貌似很完美的解決了上述效率的問題,它或許在并發量不多,安全性不太高的情況能完美運行,但是,這種方法也有不幸的地方。問題就是出現在這句`instance = new Singleton(); `
在JVM編譯的過程中會出現指令重排的優化過程,這就會導致當 instance實際上還沒初始化,就可能被分配了內存空間,也就是說會出現 instance !=null 但是又沒初始化的情況,這樣就會導致返回的 instance 不完整(可以參考:http://www.360doc.com/content/11/0810/12/1542811_139352888.shtml)。
調用:`Singleton.getInstance().method();`
優點:在并發量不多,安全性不高的情況下或許能很完美運行單例模式
缺點:不同平臺編譯過程中可能會存在嚴重安全隱患。
補充:在android圖像開源項目Android-Universal-Image-Loader (https://github.com/nostra13/Android-Universal-Image-Loader) 中使用的是這種方式。
(4)內部類的實現
內部類是一種好的實現方式,可以推薦使用一下:
~~~
public class SingletonInner {
/**
* 內部類實現單例模式
* 延遲加載,減少內存開銷
*
* @author xuzhaohu
*
*/
private static class SingletonHolder {
private static SingletonInner instance = new SingletonInner();
}
/**
* 私有的構造函數
*/
private SingletonInner() {
}
public static SingletonInner getInstance() {
return SingletonHolder.instance;
}
protected void method() {
System.out.println("SingletonInner");
}
}
~~~
調用:`SingletonInner.getInstance().method();`
優點:延遲加載,線程安全(java中class加載時互斥的),也減少了內存消耗
(5)枚舉的方法
這是網上很多人推薦的一種做法,但是貌似使用的不廣泛,大家可以試試,
~~~
/**
* @function:單例模式枚舉實現
* @author xuzhaohu
*
*/
public enum SingletonEnum {
/**
* 1.從Java1.5開始支持;
* 2.無償提供序列化機制;
* 3.絕對防止多次實例化,即使在面對復雜的序列化或者反射攻擊的時候;
*/
instance;
private String others;
SingletonEnum() {
}
public void method() {
System.out.println("SingletonEnum");
}
public String getOthers() {
return others;
}
public void setOthers(String others) {
this.others = others;
}
}
~~~
調用:`SingletonEnum.instance.method();`
優缺點:如代碼中注釋。
上面主要講了單例模式5種創建方法,大家可以根據其優缺點進行個人實際項目中的使用。講的屬于拋磚引玉,大家多提意見。
參考:http://zz563143188.iteye.com/blog/1847029