单例模式---设计模式(一)
單例模式:確保一個類最多只有一個實例,并提供一個全局訪問點
單例模式類圖:
類圖說明:
首先說明一下該類圖中的符號:
類:
使用三層矩形框表示
第一層:顯示類的名稱,如果是抽象類,則就用斜體顯示
第二層:字段和屬性
第三層:類的方法
“+”:表示public
“-”:表示private
“#”:表示protected
接口:
使用兩層矩形框表示,與類圖的區別主要是頂端有<<interface>>顯示
第一層:接口的名稱
第二層:接口的方法
繼承類(extends):
用空心三角形+直線表示
實現接口(implements):
用空心三角形+虛線表示
關聯(Association):
用實線箭頭來表示
聚合(Aggregation):
用空心菱形+實線箭頭來表示
聚合:表示一種弱的‘擁有’關系,體現的是A對象可以包含B,但B對象不是A對象的一部分,例如:公司和員工
組合(Composition):
用實心菱形+實線箭頭來表示
組合:部分和整體的關系,并且生命周期是相同的。例如:人和手
依賴(Dependency):
用虛線箭頭來表示
例如:動物和氧氣
單例模式
Singleton類稱為單例類,通過使用private的構造函數,確保了在一個應用中只產生一個實例,并且是自行實例化的(在Singleton中自己使用new Singleton())。
單例模式的通用代碼:
餓漢式:
懶漢式:
package singletontest;/*** 懶漢模式* 區別:餓漢模式的特點是加載類時比較慢,但運行時獲取對象的速度比較快,線程安全* 懶漢模式特點是加載類時比較快,但運行時獲取對象速度比較慢,線程不安全* @author 張耀暉**/ public class Singleton2 {//1.將構造方法私有化,不允許外邊直接創建對象private Singleton2(){}//2.聲明類的唯一實例,使用private static修飾private static Singleton2 singleton2;//3.提供一個用于獲取實例的方法,使用public static修飾public static Singleton2 getInstance(){if(singleton2==null){singleton2 = new Singleton2();}return singleton2;}} package singletontest;public class Test {public static void main(String[] args) {//餓漢模式Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();if(s1==s2){System.out.println("s1和s2是同一個實例");}else{System.out.println("s1和s2不是同一個實例");}//懶漢模式Singleton2 s3 = Singleton2.getInstance();Singleton2 s4 = Singleton2.getInstance();if(s3==s4){System.out.println("s3和s4是同一個實例");}else{System.out.println("s3和s4不是同一個實例");}}}運行結果:
注意:
懶漢式是存在線程不安全問題的。
懶漢式在低并發的情況下有可能不會出現問題,但是當高并發的情況下則可能在內存中出現多個實例。
eg:如果一個線程A執行到singleton2 = new Singleton2(),但還沒有獲得對象(對象初始化是需要時間的),第二個線程B也在執行,執行到singleton2==null的判斷,那么線程B獲得判斷條件也是為真,于是繼續運行下去,線程A獲得一個對象,線程B也獲得一個對象,在內存中就出現了兩個對象。
解決懶漢式的線程不安全問題的方法:
在getInstance()方法前加synchronized關鍵字。不過這樣的話只適應調用實例對象少的情況,如果調用實例對象比較頻繁synchronized就會影響系統的執行效率。那么就建議使用餓漢式。
餓漢式也有一定的問題,在不使用類的實例對象的時候也會創建該類的實例對象,造成一定的資源浪費。
單例模式的優點
?由于單例模式在內存中只有一個實例,減少了內存開支,特別是一個對象需要頻繁的被創建、銷毀,而且創建或銷毀時性能又無法優化,單例模式的優勢就非常明顯;
?由于單例模式只生成一個實例,減少了系統性能開銷,當一個對象的產生需要比較多的資源時,如讀取配置、產生其他依賴對象時,則可以通過在應用啟動時直接產生一個單例對象,然后永久駐留內存的方式來解決(在Java EE中采用單例模式時需要注意JVM垃圾回收機制);
?單例模式可以避免對資源的多重占用,例如一個寫文件動作,由于只有一個實例存在內存中,避免對同一個資源文件的同時寫操作。
?單例模式可以在系統設置全局的訪問點,優化環共享資源訪問,例如可以設計一個單例類,負責所有數據表的映射處理。
單例模式的缺點
?單例模式沒有接口,擴展很困難,若要擴展,除了修改代碼沒有第二種途徑可以實現。單例模式為什么不能增加接口呢?因為接口對單例模式是沒有任何的意義,它要求“自行實例化”,并且提供單一實例、接口或抽象類是不可能被實例化的。
?單例模式對測試是不利的。在并行開發環境中,如果單例模式沒有完成,是不能進行測試的,沒有接口也不能使用mock的方式虛擬一個對象。
?單例模式與單一職責原則有沖突。一個類應該只實現一個的邏輯,而不關心它是否是單例的,決定它是不是要單例是環境決定的,單例模式把“要單例”和業務邏輯融合也在一個類中。
單例模式的使用場景
在一個系統中,要求一個類有且僅有一個對象,如果出現多個對象就會出現“不良反應”時,則可以采用單例模式,具體的場景如下:
?要求生成唯一序列號的環境;
?在整個項目中需要有訪問一個共享訪問點或共享數據,例如一個Web頁面上的計數器,可以不用每次刷新都記錄到數據庫中,使用單例模式保持計數器的值,并確保是線程安全的;
?創建一個對象需要消耗的資源過多,如要訪問IO、訪問數據庫等資源;
?需要定義大量的靜態常量和靜態方法(如工具類)的環境,可以采用單例模式(當然,也可以直接聲明為static的方式);
單例模式的擴展
現在有一個問題:如果要求一個類只能產生固定數量(大于1個)的對象怎么辦?
package com.test.singletonTest;import java.util.ArrayList; import java.util.Random;/*** 單例模式的擴展,產生固定數量的(大于1個)的實例對象* 2015年9月17日 下午5:08:15* @author 張耀暉**/ public class SingletonTest {private static int maxnum = 3;//定義最多能產生的實例對象的數量private static ArrayList<SingletonTest> singletonList = new ArrayList<SingletonTest>();//定義一個集合,容納所有的實例對象private static ArrayList<String> singletonNameList = new ArrayList<String>();//定義一個集合,容納所有對象的私有屬性//當前實例對象的標號private static int countOfNum;//產生所有的對象static{for (int i = 0; i < maxnum; i++) {singletonList.add(new SingletonTest("實例對象:"+i+1));}}// //將類中默認的無參構造方法重寫為private,防止在外部創建該類的實例對象 // private SingletonTest(){ // // }//傳入實例對象的名稱,創建實例對象private SingletonTest(String name){singletonNameList.add(name);}//隨機獲得一個實例對象public static SingletonTest getInstance(){Random random = new Random();countOfNum = random.nextInt(maxnum);//隨機取出一個實例對象SingletonTest singletonTest = singletonList.get(countOfNum);return singletonTest;}//獲取實例對象的私有屬性public static String getSingletonName(){String name = singletonNameList.get(countOfNum);return name;}}總結
以上是生活随笔為你收集整理的单例模式---设计模式(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android网络图片加载缓存处理库的使
- 下一篇: 工厂模式---设计模式(二)