**:
注意:我的文章一般都是傾向於原理性介紹,內含**可能存在錯漏,也絕對不是大家可以拿來就用的標準**。模式設計重要在於思想,而不在於如何實現。
考慮「建立型模式-工廠方法(factory method)」中,我們對於每種虛構造器物件,我們都只需要乙個例項。類似的情況還在許多地方出現,概括起來就是:某種型別,只需要也只能被例項化一次,這種只能有單一例項的型別稱為乙個單件類,或者說這種程式設計模式為單件模式。
可以使用全域性物件方式來定義乙個型別的例項,並通過約定來保證它的單一性。這對於小的程式尤其是乙個人寫的程式往往是可行的,但是對於大的專案則往往不行。專案中的組**員素質是參差不齊的,他們對專案中各種各樣的約定也不了解,在以下三種情況下,約定往往會被打破:
組員不尊重約定,我行我素程式設計
組員疏忽,忘記了約定
新進組員,根本不知道有這個約定
這種情況下,使用約定的方式保證單一性是很明顯不可能的。為了保證單一性,必須通過編譯器提供的機制來實現。
由於每個類被例項化時,例項化的**必須能訪問建構函式,如果建構函式不是public的,則例項化就會被禁止。為此,可以把單件類的建構函式設定成private或者protected的,這樣使用者就不能任意的例項化該類。對於乙個簡單的單件,它一般不需要被繼承,這種情況下,把建構函式設定成private是最好的(這樣禁止繼承)。
既然我們限制了建構函式,主動維護物件的例項化過程,那麼同時維護析構過程也是乙個合理的習慣。因此,建議大家使析構函式的訪問修飾和建構函式的一致。即建構函式是private的,析構函式也是private,如果建構函式是protected的,則析構函式也是protected的。
下面以單件類csingleton來說明,首先說明補需要派生的簡單單件。
對於簡單的單件,首先需要把建構函式和析構函式定義成private的,因此它首先被定義成如下所示的類:
class csingleton由於我們隱藏了構造和析構函式,還必須為這個類提供建立自己例項和刪除例項的介面。對於建立例項,我們可以用乙個static成員函式實現(由於在這個介面函式被呼叫之前,還不存在任何例項,因此該函式必須是static的),對於刪除例項,則可以用乙個delete成員函式來實現。為了保證例項的單一性,我們還必須儲存例項的指標,為此,我們需要乙個靜態指標成員變數來儲存例項的位址。增加了這些介面的類如下:;
//標頭檔案對於簡單的單件,以上所做的就足夠了,使用者可以在此基礎上新增自己的成員函式和變數進行處理。class csingleton
;//cpp檔案
csingleton * csingleton ::s_psingleton = (csingleton*)0;
csingleton * csingleton ::instance()
return s_psingleton;
}void csingleton::delete()
delete this;
}
考慮我們在「工廠方法」一文中所述,對於每個cshape類派生類,我們都需要給他們建立乙個虛構造器,這一組構造器都應該是單件類。如果我們按照前文方法對每個虛構造器都進行單件設計,也不是不可以,但是這樣將非常複雜。採用一種「註冊」機制來做,將降低工作量。
為了實現這一目標,首先為這些單件類定義乙個共同的根,在「工廠方法」中,該根就是cshareruntimeclass,這個根本身不需要也不能被例項化,但是為了保證派生類的單件性,這個根的建構函式和析構函式必須保證是protected的。我們建立乙個全域性的**,儲存所有被例項化的子類物件的指標,為了保證單一性,這些子類都被分配乙個唯一的id號。由基類的建構函式在這個**中註冊這個例項化的類。為此,修改csingleton類如下:
class ctablesingleton;對於派生類而言,它必須隱藏自己的建構函式和析構函式,並提供乙個例項化自己的介面。為了做到這一點,可以通過定義一些巨集來實現,可以用下面巨集實現目標:class csingletonptr
; operator ctablesingleton * & ();
};class ctablesingleton
;csingletonptr ctablesingleton:: s_aptable[max_objects];
//註冊函式
void ctablesingleton::registerself()
g_aptable[m_uid]= this;
}//反註冊
void ctablesingleton::unregisterself()
g_aptable[m_uid]= null;
}//建構函式
ctablesingleton::ctablesingleton(uint uid):m_uid(uid)
//析構函式
ctablesingleton::~ctablesingleton(uint uid):m_uid(uid)
//從**中搜尋子類的函式
ctablesingleton* ctablesingleton::findinstance(uint uid)
return s_aptable[uid];
}
#define declare_singleton(classname) /定義了這些巨集以後,那麼從ctablesingleton派生的類只要按照下列方式插入巨集即可正確工作:public:/
static classname * instance();/
void delete();/
private:/
classname();
#define implement_singleton(classname,id) /
classname * classname::instance()/
else/
}/void classname::delete()///
classname :: classname():ctablesingleton(id)
//標頭檔案這裡我們只提供了乙個不帶引數的建構函式,如果建構函式的引數固定,那麼我們還可以提供方便的巨集,如果不固定,只有一一設計了。但是注意的是,必須提供ctablesingleton(uid)構造初始化。class cderivedclass:public ctablesingleton
;//cpp檔案
implement_singleton(classname,derived_class_id)
使用單件有如下好處:
singleton類的例項不在全域性變數空間中,避免汙染全域性變數空間
一般情況下,這些例項都是在使用時建立,實現按需分配
可控的類例項化,將使得程式設計者能夠更精確的控制類的行為
單件也可以擴充套件到例項數量有限的情況,這裡就不再贅述,只要讀者能清晰單件的原理,這些都不是很困難。
Singleton單件 建立型模式
模式分類 從目的來看 建立型模式 負責物件建立。結構型模式 處理類與物件間的組合。行為型模式 類與物件互動中的職責分配。從範圍來看 類模式處理類與子類的靜態關係。物件模式處理物件間的動態關係。動機 如果繞過常規的構造器,提供一種機制來保證乙個類只能有乙個例項。例項如下 public class si...
建立型模式類(單件模式)
2 void main 3 13 all are the same instance use b1 arbitrarily14 load balance 15 server requests15 for int i 0 i 15 i 16 19 wait for user20 console.rea...
建立型模式 單例模式
餓漢式 package com.hfview.designmode.signle 1.餓漢式 就是在初始化成員變數的時候就獲取例項物件 2.public class signlemode private signlemode 懶漢式 package com.hfview.designmode.sig...