註:今天不知道怎麼的CSDN的部落格貼代碼和貼圖片的按鈕好像有點問題,我貼不出來,只能用複製代碼說明問題了
至於單例模式,是設計模式中最為基本的模式之一,說直白點就是在程式中確保任何時候都只有一個執行個體,比如windows的檔案管理類,還有就是在cocos2dx中的遊戲導演類等等,那麼如何來確保任何時候都只能有一個執行個體勒?這個時候我們的static就起作用了!
前幾天一個朋友問我cocos2dx中的這一行代碼是什麼意思,為什麼要這麼寫,代碼如下:
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
他是這麼問的:為什麼不執行個體一個對象來調用成員函數,而每次調用都要把CCDirector::sharedDirector()加上去,這樣豈不是很麻煩?
是的,這樣是麻煩了點,但是相比他給我們帶來的好處,這點麻煩就不值一提了,他保證了在整個程式運行期間只有一個執行個體,不會有其他對象產生,一則節省了空間,二則為我們的管理提供了方便!
單例模式的實現,在這裡我類比一個CCDirector,代碼如下:
class CCDirector
{
private:
static CCDirector *pDirector;
. .......
. .......
public:
static CCDirector* sharedDirector();
{
.........
return pDirector;
}
.......
};
顯然這樣的類聲明就達到了上面那條文法的標準,那麼我們該怎麼來執行個體化這個唯一的執行個體勒?在這裡有兩個可選模式:
懶漢式:是典型的以時間換取空間的例子,就是每次擷取執行個體時都要進行判斷,看是否要建立執行個體,浪費判斷時間。當然如果一直沒有人用的話,就不會建立執行個體,則是節約空間。
餓漢式:是典型的以空間換取時間,就是說當類裝載的時候,就建立出一個執行個體,不管你用不用它,然後每次調用時就不用判斷了,節省了已耗用時間
至於這兩個模式到底哪個好,這就得自己進行時空權衡了,各有優點!
在cocos2dx中,他是使用的懶漢式執行個體化單一對象,代碼如下:
CCDirector* CCDirector::sharedDirector(void)
{
static bool s_bFirstUseDirector = true;
if (s_bFirstUseDirector)
{
s_bFirstUseDirector = false;
s_SharedDirector.init();
}
return &s_SharedDirector;
}
可以看到他定義一個static的bool變數來標記是否建立單例對象,沒有就init()一個,有就直接返回(但是我不理解的是為什麼非要加個bool,這不是多佔用幾個位元組嗎,可以直接判斷那個指標是否為空白啊!!好吧,cocosTeam Dev的高瞻遠矚,我不能體會)!
至於餓漢式,就是直接剛開始的時候調用init()函數,使這個對象指標一直存在!就不用每次判斷了
使用單例模式的注意點:
1:只能用執行個體指標嗎?不能執行個體對象嗎?
這個在很低級的書上就講到了,我記得沒錯的話,譚浩強的書上都說過:結構體之中不能含有本身的結構體變數,當然可以含有指向本身結構體的指標!所以在類中當然也是一樣啊,這種低級錯誤在新手裡面可是很常見!
2:單例模式只是為了節省資源嗎?
首先要說明的是,在一些情況下使用單例模式是可以達到節省資源的目的,但是單例模式的意圖不只是為了節省資源,如果僅僅為了節省資源就使用單例模式的話可能造成單例模式的濫用。單例模式是為了確保在整個應用期間只有一個執行個體,以達到使用者的特定的使用目的。
3:單例模式的壞處
擴充困難,由於sharedDirector靜態函數沒有辦法產生子類的執行個體。如果要拓展,只有重寫那個類。
隱式使用引起類結構不清晰。比如有時候,你並不知道某個類A是單例類,當你讀類B的時候,你可能先看它標頭檔,或者類別檢視裡的內容,從這裡你無法知道A和B 關係,因為B類在實現的時候才使用A類的那個所謂的sharedDirector函數,讀不到這行,你就不會知道B類對A類的依賴關係。
導致程式記憶體泄露的問題。很多人只是調用了sharedDirector產生唯一的執行個體,卻永遠new被封裝在sharedDirector裡忘了去釋放記憶體。
4: 什麼情況下不能用單例模式
單例模式簡單易用,但是也是所有設計模式中最容易濫用的模式。當你的類想得到很好的擴充時,不能使用單例模式。
也許你的程式一開始並非一定要確保只有一個執行個體,如果你僅僅是為了節省資源而用的話,這個時候要慎用,因為隨著時間的推延也許你的程式還需要擴充。