設計模式學習 單例模式

2021-07-29 23:17:25 字數 4089 閱讀 2909

在面試的過程中屢屢被問到設計模式,出現頻率很高,可見設計模式的重要性,所以,學習設計模式刻不容緩!

先了解一下什麼是設計模式?

設計模式的定義:

設計模式是一套被反覆使用,多數人知曉的、經過分類編目的、**設計的總結,使用設計模式是為了可重用**,讓**更容易被他人理解,保證**可靠性。

設計模式的分類:按照目的可分為三類,建立型模式,結構型模式,行為型模式;按照範圍,即模式主要處理類之間的關係還是物件之間的關係分為類模式和物件模式

設計模式主要被廣泛應用於物件導向程式設計;

從最簡單的單例模式開始學起:單例模式,根據名字拆分就可以知道這個模式的意思,即單個例項的模式;

什麼是單個例項的模式,既然是物件導向,那麼乙個類只允許產生乙個例項物件的話,就是單例模式;

單例模式按照設計模式的分類屬於建立型模式和物件模式

為什麼要有單例模式:動機?

最經典也是最容易理解的例子:用windows的都知道,同一時刻只能開啟乙個任務管理器,不會彈出多個的,為什麼呢?因為系統的狀態是每時每刻都在變化的,如果你可以同時開啟多個任務管理器,而這些管理器顯示的內容出現不一致的情況,是不是容易引起使用者誤解;而如果多個視窗的顯示內容一致的話,開啟多個視窗是不是很浪費資源;單例模式就是為了解決這種問題而產生的,當前類只允許你擁有乙個真實的物件,如果你繼續申請,依然返回同乙個物件;

單例模式的標準定義:單例模式確保某乙個類只有乙個例項,而且自行例項化並向整個作業系統提供這個例項,這個類成為單例類,它提供全域性的訪問方法。

單例模是一種物件建立型模型,單例模式又名單件模式或單態模式

上面說的都是概念,不了解是不行的,但是只看概念是不能完全理解的,所以,**才是真諦!

通過了解單例模式的概念,我們想要設計出這樣乙個類,該如何設計呢?

code is cplusplus

餓漢單例,即在最開始的時候,靜態物件就已經建立完成;

即類中包含乙個靜態成員指標,該指標指向該類的乙個物件,提供乙個公有的靜態成員方法,返回該物件指標;為了使得物件唯一,還需要將建構函式設為私有;

class

singleton

};//靜態成員必須在類外進行初始化

singleton* singleton::intance = new singleton();

那麼,我們現在要怎麼進行測試呢? 測試哪幾個方面呢?

int main()

上面的mian中,我們主要對單例模式的特點進行了測試,發現,我們無法在其它地方再建立乙個新的singleton物件,即下面的兩種方法都會失敗,這要歸功於私有的建構函式;

singleton tmp;      

singleton* ptr =new singleton();

然後,我們注意到,在剛進入main函式,我們就列印了一句「」main begin「」,為什麼要在這裡加入一句輸出語句呢?

因為我們此時的單例模式採用的是餓漢單例,所以,哪怕你還沒用到我這個物件,我也會先建立乙個出來,先佔著,即所謂的餓漢,其實就是類似於全域性變數的構造是在進入main函式之前的原理,在這裡驗證一下,還有最後的比較兩個通過共有的靜態成員方法返回的物件指標是否一致來驗證我們單例模式返回的是同乙個物件;

結果:

上面說的是餓漢單例模式,但是這個模式有個不好的地方就是,如果我一直不使用這個物件,而這個物件是已經存在的,它會一直佔著那塊記憶體不那啥,所以啊,比較懶的人就不願意那麼早就準備好;

單例模式之懶漢單例:

所謂懶漢模式,就是盡可能晚的建立這個物件的例項,即在單例類第一次被引用時將自己初始化;其實c++裡很多地方都是類似這樣的思想,比如晚繫結,寫時拷貝技術等,就是盡量使資源的利用最大化,不要讓空閒的人還佔著有限的資源;

懶漢單例的實現:其實就是將靜態物件指標初始化為null,當單例類被引用的時候,先進行判斷指標是否為null,為null的時候再去例項乙個物件,不會null時,直接返回靜態物件指標;達到保證只有乙個例項的目的;

懶漢單例類:

class

singleton

};//靜態成員必須在類外進行初始化

singleton* singleton::intance = null;

懶漢單例類和餓漢單例唯一的不同就是,這個唯一的例項建立的時機不同;是一種按需分配的方式;

小結一下

單例模式的實現過程中,需要注意以下三點:

單例類的建構函式為私有;

提供乙個自身的靜態私有成員變數;

提供乙個共有的靜態工廠方法;

單例模式的執行緒安全問題:

----《劍指offer》單例模式學習
以懶漢單例為例,如果此時多執行緒進行操作,簡單點以兩個執行緒為例,假設pthread_1剛判斷完 intance 為null 為真,準備建立例項的時候,切換到了pthread_2, 此時pthread_2也判斷intance為null為真,建立了乙個例項,再切回pthread_1的時候繼續建立乙個例項返回,那麼此時就不再滿足單例模式的要求了, 既然這樣,是因為多執行緒訪問出的問題,那我們就來加把鎖,使得執行緒同步;

以偽**的形式展現(省略pthread_mutex_lock/ulock):

static singleton*  getsingleton()

我們在判空並建立例項的時候加一把鎖,則每個執行緒都需要申請鎖,進行互斥的訪問,以達到同步的目的;

那麼我們這樣寫的**是沒有問題的,但是效率可能有點低,因為我們加鎖的代價其實是很大的,那麼有沒有什麼改進的地方可以盡可能少的加鎖呢?

這就是加鎖的注意點,不同的加鎖方式帶來的效率可能完全不同,比如,此時如果我們在加鎖之前再加乙個判斷,if ( intance == null),這樣的話,如果靜態例項已經存在則不會進行加鎖,同時也解決了上面所說的剛開始的時候多執行緒進行建立的同步問題;

偽**如下:

static singleton*  getsingleton()

到這裡,c++的單例模式就差不多了,劍指offer上面還提到了c#建立單例模式的方法;

單例模式的優點

提供了對唯一例項的受控訪問。因為單例類封裝了它的唯一例項,所以它可以嚴格控制客戶怎樣以及何時訪問它;

由於在系統記憶體中只存在乙個物件,因此可以節約系統資源,對於一些需要頻繁建立和銷毀的物件,單例模式無疑可以提高系統的效能。

允許可變數目的例項,基於單例模式我們可以擴充套件,使用與單例控制相似的方法來獲得指定個數的物件例項。(即單例類內有多個靜態物件指標成員,每次當單例類被引用時隨機分配乙個例項物件);

單例模式的缺點

因為單例模式沒有抽象層,所以單例類的擴充套件有很大的困難;

單例類的職責過重,即是工廠角色,提供了工廠的方法,同時又充當了產品的角色;

濫用單例類會帶來一些負面問題;

單例模式的適用場景

系統只需要乙個例項物件,或者考慮到資源消耗的太大而只允許建立乙個物件。

客戶呼叫類的單個例項只允許使用乙個公共訪問點,除了該訪問點之外不允許通過其它方式訪問該例項.(就是共有的靜態方法);

---參考《設計模式》劉偉主編

學習設計模式 單例模式

適用於 優點 缺點 1.懶漢式 public class singleton public static synchronized singleton getinstance return uniqueinstance 2.餓漢式 public class singleton public stat...

設計模式學習 單例模式

單例模式是一種常用的軟體設計模式。通過單例模式可以保證系統中乙個類只有乙個例項而且該例項易於外界訪問,從而方便對例項個數的控制並節約系統資源。如果希望在系統中某個類的物件只能存在乙個,單例模式是最好的解決方案。1.單例模式特點 2.單例模式作用 3.單例模式種類 a.餓漢式 b.懶漢式 c.懶漢式 ...

學習設計模式( ) 單例模式

定義 確保乙個類只有乙個例項,而且自行例項化並向整個系統提供這個例項。型別 建立類模式 單例模式應該是23種設計模式中最簡單的一種模式了。它有以下幾個要素 單例模式現在主流推薦第一種雙重檢查型。以前流行的有根據例項化物件時機的不同有分為兩種 一種是餓漢式單例,一種是懶漢式單例。餓漢式單例在單例類被載...