1. 程式人生 > >[設計模式]單例模式

[設計模式]單例模式

釋放 常用 覆寫 這樣的 訪問 客戶端瀏覽器 創建 article net

引言

做為已經開發9年多的我,最近感覺有點迷茫,技術更新太快,有點跟不上這麽快的節奏,在開始工作時,一直也聽領導說23種設計模式,當時也看了視頻,看完也沒有太大的收獲,在工作中有的時候也是為了把設計模式強加到代碼中,最近在看設計模式時,確實有了更深刻的理解。在此我還是建議熱愛編程的同行,“如果連自己喜歡的工作,都做不好,那麽活著就太空虛了,男人麽就應該對自己恨一點。如果你現在沒有得到你想要的生活,只能說明你對自己還不夠狠”。言歸正傳,說說今天的單例模式。

單例模式定義

單例模式是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱為單例類的特殊類。通過單例模式可以保證系統中一個類只有一個實例而且該實例易於外界訪問,從而方便對實例個數的控制並節約系統資源。如果希望在系統中某個類的對象只能存在一個,單例模式是最好的解決方案。

單例模式類圖

技術分享

(類圖來自:http://www.cnblogs.com/zhili/p/SingletonPatterm.html,這裏借用一下)

常見的單例模式

/// <summary>
/// 餓漢式
/// </summary>
public sealed class Singleton
{
/// <summary>
/// 私有構造函數
/// </summary>
private Singleton()
{

}
private static readonly Singleton _Instance = new Singleton();//定義私有的靜態變量
public static Singleton Instance
{
get
{

return _Instance;
}
}
}

優點:   1.線程安全   2.在類加載的同時已經創建好一個靜態對象,調用時反應速度快。 3.通過sealed修飾類,阻止派生類的出現,因為派生可能會增加實例。 缺點:   資源效率不高,可能GetInstance()永遠不會執行到,但執行該類的其他靜態方法或者加載了該類(class.forName),那麽這個實例仍然初始化。

/// <summary>
/// 懶漢式
/// </summary>
public sealed class Singleton
{
/// <summary>
/// 私有構造函數
/// </summary>
private Singleton()
{

}
private static Singleton _instance = null;
private static readonly object obj= new object();
public static Singleton GetInstance
{
get
{
if(_instance==null)
{
lock(obj)
{
if(_instance==null)
{
_instance = new Singleton();
}
}
}
return _instance;
}
}
}

優點:

1:懶漢式面臨線程安全的問題,通過雙重鎖定這樣的處理才可以保證安全。 2:單例可以 被延遲加載。 應用場景: 數據庫操作類不宜使用singleton模式 不要將數據庫連接做成單例,因為一個系統可能會與數據庫有多個連接,並且在有連接池的情況下,應當盡可能及時釋放連接。Singleton模式由於使用靜態成員存儲類實例,所以可能會造成資源無法及時釋放,帶來問題。 做項目做的多了,所以考慮問題的方向也不一樣了。以前剛開始只是以實現功能為目的,美觀、實現方式、代碼邏輯、執行效率等等,幾乎不考慮。 然而要想成為合格的軟件設計師,軟件的設計就必須全面周到,不僅僅只是考慮如何開發,更多的要考慮軟件的發展和維護。 所以平時的學習中多思考多理解是非常重要的。 在學習DRP中,我們都知道王勇把業務邏輯層(Manager、servlet)都幾乎做成的單例模式。我當時就思考為何他要這麽做呢? 漸漸的我明白了,而且是切身的理解了。 在用.net開發web項目的時,在UI層我們要實例化BLL層的類,然而正因為是web開發,如果按照咱原來的寫法(如下) protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { News news = new NewsManager().SelectById(newsid); //News:新聞實體類,為Model層。 NewsManager:BLL層的類 } } 那麽客戶端只要與服務器需要交互一次就要執行一次Page_Load事件【因為與服務器交互後客戶端瀏覽器會刷新頁面】,那麽就要實例化一次NewsManager(),這還僅僅是Page_Load的事件,往往還會有別的事件,比如按鈕單擊事件,因為UI層與BLL層的交互是非常平凡的。 試想下這麽多次重復的New的次數,是多麽的浪費資源啊,即便把NewsManager設置成該頁面的全局變量,還是免不了每刷新一次就實例化一次的弊端。 所以把BLL層的類做成單例模式是出於對服務器資源優化的一個應用。 關於單例模式的應用,我目前了解到的有:配置文件、打開窗口、工廠模式的工廠類、再有就是今天說的BLL層管理類。 如果各位還有對於單例模式應用和技巧的見解還請多多請教 BO層為什麽設計為單例模式? 1、首先要理解每一個BO實例是用來處理用戶的一類請求操作的,即然是用來處理一類操作,那麽所有的操作都可以用一個實例來完成即單例,只要不存在實例變量,那麽就不會發生線程安全的問題。此時如果設計為多例的,並且不存在實例變量的情況,那麽新實例和舊實例是沒有任何區別的,都是執行同一類操作,處理用戶的同一類請求。那麽這時多實例只會占用更多的內存空間,沒有任何益處。 2、理解線程棧的問題。對於用戶的每一次請求操作,都有一個線程來負責該用戶的請求處理,那麽這個線程在處理用戶業務的同時,會在內存中分配一段內存區域,該內存區域存放了用戶所調用的方法中的變量,我們稱該內存區域為線程棧,線程棧中除了存有方法中的局部變量外,還持有調用該方法的單實例對象的一個引用。因為每一個線程棧都存儲了當前單實例對象對應方法中局部變量的不同版本,那麽這樣每一個線程的方法操作都不會影響其他線程的方法操作,所以不存在線程安全的問題了。 介紹了單例,有些人可能感覺靜態類也可以完成上面的應用場景,再次我在這總結一下單例和靜態類的區別,以供大家學習 靜態類和單例模式區別 觀點一:(單例) 單例模式比靜態方法有很多優勢: 1::單例可以繼承類,實現接口,而靜態類不能(可以集成類,但不能集成實例成員); 2:單例可以被延遲初始化,靜態類一般在第一次加載是初始化; :3::單例類可以被集成,他的方法可以被覆寫; 最後,或許最重要的是,單例類可以被用於多態而無需強迫用戶只假定唯一的實例。舉個例子,你可能在開始時只寫一個配置,但是以後你可能需要支持超過一個配置集,或者可能需要允許用戶從外部從外部文件中加載一個配置對象,或者編寫自己的。你的代碼不需要關註全局的狀態,因此你的代碼會更加靈活。 觀點二:(靜態方法)靜態方法中產生的對象,會隨著靜態方法執行完畢而釋放掉,而且執行類中的靜態方法時,不會實例化靜態方法所在的類。如果是用singleton, 產生的那一個唯一的實例,會一直在內存中,不會被GC清除的(原因是靜態的屬性變量不會被GC清除),除非整個JVM退出了。這個問題我之前也想幾天,並且自己寫代碼來做了個實驗。 觀點三:(Good!) 由於DAO的初始化,會比較占系統資源的,如果用靜態方法來取,會不斷地初始化和釋放,所以我個人認為如果不存在比較復雜的事務管理,用singleton會比較好。個人意見,歡迎各位高手指正。 http://blog.csdn.net/v1v1wang/article/details/5511756 ----------------------------------------------------------------------------------------------------------- 這裏暫且把單例模式限定為不是全用靜態函數實現的。 1。使用的方便性:如果需要初始化工作,單例模式可以在構造函數裏面完成,全靜態函數的類需要一個額外的函數來完成初始化工作,而且使用者如果沒有調用這個initialize函數,那麽後續的操作就會有問題,構造函數會被默認調用,所以使用起來比較簡單,對使用者做出了最少的假設。 2。初始化時機:單例模式初始化比較靈活,可以在需要的時候初始化,而全靜態函數必然導致成員全為靜態成員,靜態成員是在編譯時就初始化好了。如果初始化成本比較昂貴,並且程序裏面未必一定使用這個類,那這將是單例模式的一個很大優勢。順便說一下全局變量,全局變量的初始化順序是未指定的。 例如 全局變量int a; int b;編譯器是先初始化a還是先初始化b?我想大家只能靠猜,或者在某個編譯器上實驗一下給出答案,一旦要是有個新編譯器,結果又會是什麽樣子呢? 3。最重要的區別:單例模式可以有多態,而全靜態的類不能支持多態。 總結: 單例保證一個類只有一個實例,並提供對外的只有一個全局訪問點。 第一次寫隨筆,裏面可能有些是在網上是借鑒,以此總結,便於自己記憶,如果可以給其它帶來幫助的,就請大家看過,別用搬磚就可以了!!!!!!

[設計模式]單例模式