『設計模式』我就要一個對象,你別給我這麼多好不好!---單例模式

引入

作爲一個現代社會文明青年,我覺得一夫一妻制非常合理。有些男人富裕了點,就想多照顧幾個女人的行爲,真的不可取,有的時候法律在這些面前顯得難以生效,畢竟重婚罪又不能限制婚外情,多找幾個對象。
在這裏插入圖片描述
人尚且如此,何況程序呢,面對只能實例化一個對象的程序,我們該如何處理呢?
我們今天就來看一下單例模式!
在這裏插入圖片描述

單例模式

單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。

這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。

注意:

  • 單例類只能有一個實例。
  • 單例類必須自己創建自己的唯一實例。
  • 單例類必須給所有其他對象提供這一實例。

目的:

保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。

主要解決:

一個全局使用的類頻繁地創建與銷燬。

何時使用:

當您想控制實例數目,節省系統資源的時候。

優點

實例控制
單例模式會阻止其他對象實例化其自己的單例對象的副本,從而確保所有對象都訪問唯一實例。
靈活性:
因爲類控制了實例化過程,所以類可以靈活更改實例化過程。

缺點

開銷:
雖然數量很少,但如果每次對象請求引用時都要檢查是否存在類的實例,將仍然需要一些開銷。可以通過使用靜態初始化解決此問題。
可能的開發混淆:
使用單例對象(尤其在類庫中定義的對象)時,開發人員必須記住自己不能使用new關鍵字實例化對象。因爲可能無法訪問庫源代碼,因此應用程序開發人員可能會意外發現自己無法直接實例化此類。
對象生存期:
不能解決刪除單個對象的問題。在提供內存管理的語言中(例如基於.NET Framework的語言),只有單例類能夠導致實例被取消分配,因爲它包含對該實例的私有引用。在某些語言中(如 C++),其他類可以刪除對象實例,但這樣會導致單例類中出現懸浮引用。
不符合單一職責原則
沒有接口,不能繼承,與單一職責原則衝突,一個類應該只關心內部邏輯,而不關心外面怎麼樣來實例化。

實現:

單例模式的 UML 圖
在這裏插入圖片描述

創建一個 Singleton 類

package 單例模式;

public class Singleton {
	private static Singleton singleobj;

	private  Singleton() {}//通過private限定,不能通過new建立對象,也不能繼承(可以有繼承操作,但是無意義)
	public  Singleton newinstance()
	{
		if(singleobj!=null) return singleobj;
		else {
			singleobj=new Singleton();
			return singleobj;
		}
	}
	 
	public void dosomething()
	{
		System.out.println("一個女朋友就夠了!!!");
	}
	
	
}

從 singleton 類獲取唯一的對象

package 單例模式;

public class SingletonTest {

	public static void main(String[] args) {
		// SingleObject object = new SingleObject();
		// 編譯時錯誤:構造函數 SingleObject() 是不可見的

		Singleton SingleT = Singleton.newinstance();      //獲取唯一可用的對象
		SingleT.dosomething();

	}

}

執行程序,輸出結果:

一個女朋友就夠了!!!

進階

看完前面的實列,但是並不能真正的應用在實際應用中,因爲在現實的中更多的涉及到線程的問題,所以,給大家展示一下以下的方法。

1. 懶漢式(線程不安全,不支持多線程)

對比:

  • 是否 Lazy 初始化:是
  • 是否多線程安全:否
  • 實現難度:易

描述: 這種方式是最基本的實現方式,也就是前面提到的方式,這種實現最大的問題就是不支持多線程。因爲沒有加鎖 synchronized,所以嚴格意義上它並不算單例模式。
這種方式 lazy loading 很明顯,不要求線程安全,在多線程不能正常工作,在多線程系統的今天,一般很少使用。

實例

package 單例模式;

public class Singleton {
	private static Singleton singleobj;
	
	private  Singleton() {}//通過private限定,不能通過new建立對象,也不能繼承(可以有繼承操作,但是無意義)
	
	public  Singleton newinstance(){
		if(singleobj!=null) return singleobj;
		else {
			singleobj=new Singleton();
			return singleobj;
		}
	}
	
	public void dosomething()	{
		System.out.println("一個女朋友就夠了!!!");
	}
}
2. 懶漢式(線程安全,支持多線程)

對比:

  • 是否 Lazy 初始化:是
  • 是否多線程安全:是
  • 實現難度:易

描述: 這種方式具備很好的 lazy loading,能夠在多線程中很好的工作,但是,效率很低,99% 情況下不需要同步,可以說是一種以時間換空間的方法。

  • 優點:
    第一次調用才初始化,避免內存浪費。
  • 缺點:
    必須加鎖 synchronized 才能保證單例,但加鎖會影響效率,雖然getInstance() 的性能對應用程序不是很關鍵(該方法使用不太頻繁)

實例

package 單例模式;

public class Singleton {
	private static Singleton singleobj;

	private Singleton() {
	}// 通過private限定,不能通過new建立對象,也不能繼承(可以有繼承操作,但是無意義)

	public static synchronized Singleton getinstance() {//synchronized 才能保證多線程單例
		if (singleobj != null)
			return singleobj;
		else {
			singleobj = new Singleton();
			return singleobj;
		}
	}

	public void dosomething() {
		System.out.println("一個女朋友就夠了!!!");
	}
}
3. 餓漢式(線程安全,支持多線程)

對比:

  • 是否 Lazy 初始化:否
  • 是否多線程安全:是
  • 實現難度:易

描述:
這種方式比較常用,但容易產生垃圾對象。即以空間換時間的方式。
優點:
沒有加鎖,執行效率會提高。
缺點:
類加載時就初始化,浪費內存。
它基於 classloader 機制避免了多線程的同步問題, 雖然避免了多線程時調用getinstance時的線程問題,但是不能避免的是其他靜態方法也能創建singleton對象。

實例

package 單例模式;

public class Singleton {
	private static Singleton singleobj = new Singleton();

	private Singleton() {
	}// 通過private限定,不能通過new建立對象,也不能繼承(可以有繼承操作,但是無意義)

	public static synchronized Singleton getinstance() {
		return singleobj;
	}

	public void dosomething() {
		System.out.println("一個女朋友就夠了!!!");
	}

}

4.雙檢鎖/雙重校驗鎖 “DCL,即 double-checked locking”(線程安全,支持多線程)

對比:

  • 是否 Lazy 初始化:是
  • 是否多線程安全:是
  • 實現難度:較複雜

描述: 這種方式採用雙鎖機制,安全且在多線程情況下能保持高性能。
getInstance() 的性能對應用程序很關鍵。

實例

package 單例模式;

public class Singleton {
	 private volatile static  Singleton singleobj;

	private Singleton() {
	}// 通過private限定,不能通過new建立對象,也不能繼承(可以有繼承操作,但是無意義)

	public static synchronized Singleton getinstance() {
		 if (singleobj == null) {  
		        synchronized (Singleton.class) {  
		        if (singleobj == null) {  
		        	singleobj = new Singleton();  
		        }  
		        }  
		    }  
		    return singleobj;  
	}

	public void dosomething() {
		System.out.println("一個女朋友就夠了!!!");
	}

}
 

其餘方法: 登記式/靜態內部類,枚舉

應用給實例

配置文件,如果被系統的很多地方使用,那麼不能總是去打開文件吧,那樣很佔用資源,所以我們可以使用單例模式,返回配置文件對象。

package 單例模式;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

public class Singel_Loder { //餓漢Hunger方式
	private static Singel_Loder singleobj = new Singel_Loder();

	private Singel_Loder() {
	}// 通過private限定,不能通過new建立對象,也不能繼承(可以有繼承操作,但是無意義)
	private static Properties props = new Properties(); 
    static { 
        try { 
            props.load(new FileInputStream("配置文件.properties")); 
        } catch (FileNotFoundException e) { 
            e.printStackTrace(); 
            System.exit(-1); 
        } catch (IOException e) {        
            System.exit(-1); 
        } 
    } 

	public static  Singel_Loder getinstance() {
		return singleobj;
	}

	public Properties getpro() {
		 
		return props;
	}
}

package 單例模式;

import java.util.Properties;

public class SingletonTest {

	public static void main(String[] args) {
		Singel_Loder sloder=Singel_Loder.getinstance();
		Properties pro=sloder.getpro();
		/**
		藉助配置文件做一些事情
		
		 */
	}

}


寫在最後:
Name:風骨散人,目前是一名雙非在校大學生,預計考研,熱愛編程,熱愛技術,喜歡分享,知識無界,希望我的分享可以幫到你!名字的含義:我想有一天我能有能力隨心所欲不逾矩,不總是向生活低頭,有能力讓家人擁有富足的生活而不是爲了生計而到處奔波。“世人慌慌張張,不過是圖碎銀幾兩。偏偏這碎銀幾兩,能解世間惆悵,可讓父母安康,可護幼子成長 …”
文章主要內容:
Python,C++,C語言,JAVA,C#等語言的教程
ACM題解、模板、算法等,主要是數據結構,數學和圖論
設計模式,數據庫,計算機網絡,操作系統,計算機組成原理
Python爬蟲、深度學習、機器學習
計算機系408考研的所有專業課內容
目前還在更新中,先關注不迷路。微信公衆號,cnblogs(博客園),CSDN同名“風骨散人”

如果有什麼想看的,可以私信我,如果在能力範圍內,我會發布相應的博文!
感謝大家的閱讀!😘你的點贊、收藏、關注是對我最大的鼓勵!

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