Policy 和 Policy Classes有助於我們設計出更加安全,有效率且具有高度彈性的“設計項目”。所謂Policy,是用來定義一個class或者class template的介面,該介面以下項目之一或者全部組成:內隱類型定義,成員函數,成員變數。
template< class T ><br />struct OpNewCreator<br />{<br />static T* Create() </p><p>{<br />return new T;<br />}<br />};<br />template< class T ><br />struct MallocCreator<br />{<br />static T* Create()<br />{<br />void* pBuf = std::malloc( sizeof( T ) );<br />if( !pBuf ) return 0;<br />return new( pBuf ) T;<br />}<br />};<br />template< class T ><br />struct PrototypeCreator<br />{<br />PrototypeCreator( T* pObj == 0 )<br />: pPrototype_( pObj )<br />{<br />}</p><p>T* Create()<br />{<br />return pPrototype_ ? pPrototype_->Clone():0;<br />}</p><p>T* GetPrototype()<br />{<br />return pPrototype_;<br />}</p><p>void SetPrototype( T* pObj )<br />{<br />pPrototype_ = pObj;<br />}</p><p>private:<br />T* pPrototype_;<br />}<br />
Policies介面和一般傳統的classes介面(純虛函數集)不同,它比較鬆散,因為Policies是文法導向而非標記導向,比如:Creator明確定義的是“怎樣的文法構造符合其所規範的class”,而非“必須重寫哪些函數”,例如Creator Policy並沒有規範Create()必須是靜態或者是虛函數,它只要求class必須定義出Create(),此外規定Create()應該(但非必須)傳回一個指向新對象的指標。
如果又下面一個類設計需要適用Policy作為其基礎類:
template < class CreationPolicy ><br />class WidgetManager : public CreationPolicy<br />{<br />};<br />
當具體執行個體化的時候我們必須傳進去一個他所期望的Policy:
typedef WidgetManager< OpNewCreator<Widget> > MyWidgetMgr;
但是Policy的Template引數往往是多餘的,因為執行個體化的對象往往已經在定義之前就已經確定了他的操作對象,比如上面的WidegManager總是操作Widget對象,所以完全沒有必要每次執行個體化的時候再進行傳入操作,這樣既多餘而且危險。
這個時候程式庫可以使用“Template Template參數“來描述Policies,如下:
template < template < class Created > class CreationPolicy ><br />class WidgetManager : public CreationPolicy< Widget ><br />{<br />};<br />
要注意的是上面的Created引數其實只是一個形式引數,因此沒有什麼作用,可以省略。
typedef WidgetManager< OpNewCreator > MyWidgetMgr;
一個重要的細節就是Policy Class的解構函式,大多數的繼承類會以公用繼承的方式從某些Policies派生而來,因此使用者可以將一個這樣的繼承類自動轉為一個Policy Class,並於稍後Delete該指標,除非Policy Class定義了 一個虛解構函式,否則Delete一個指向Policy Class的指標會產生不可預期的結果。
typedef MyWidgetManager< PrototypeCreator > MyWidgetManager;
....
MyWidgetManager wm;
PrototypeCreator<Widget>* pCreator = &wm;
delete pCreator;
如果給Policy定義一個虛擬解構函式,會妨礙Policy的靜態結連特性,也會影響執行效率。許多的Policies並無任何的成員資料,純粹只規範行為。第一個虛擬函數被加入會為對象大小帶來額外的開銷(以為加入一份Vptr表),所以虛解構函式應該儘可能的避免。所以我們可以採用一個輕便而有效率的解法——定義一個非虛析構,如下:
template< class T >
struct OpNewCreator
{
static T* Create()
{
return new T;
}
protected:
~OpNewCreator() {}
};
我們可以將Policies組合起來,一般而言,一個高度可組裝化的class會運用數個Policies來達成其運作上的各個方面。一個程式庫使用者可以藉由組合不同的Policy Classes來選擇他所需的高階行為。
而建立一個基於Policy的類設計的最困難的部分,便是如何將Class正確的分解為Policies。一個準則就是,將參與Class行為的設計鑒別出來並命名。任何事情只要能以一種以上的方法解決,都應該被分析出來,並從Class中移出來成為一個Policy。
“設計“就是一種”選擇“。大多數時候我們的困難並不在於找不到解決方案,而是又太多的解決方案。你必須知道哪一組方案可以圓滿解決問題。大至構架層面,小至程式碼片段,都需要選擇。此外,抉擇是可以組合的,這給設計帶來了可怕的多樣性。Policies機制由templates和多重繼承組成。一個Class如果適用了Polices,我們稱其為host class,那是一個擁有多個template參數的class template,每一個參數代表一個policy。圍繞著Policies而設計出來的class,支援可擴充的行為和優雅的機能消減。由於採用公用繼承的原因,Policy得以通過host class提供追加功能。而host class也能運用”Policy提供的選擇性機能“執行個體出更豐富的功能。