注意:本系列博文需要对templates和STL有一定掌握。
Policies 和Policy Classes
承接上一篇博文所述,这回将介绍Policies 和Policy Classes。Policies 和Policy Classes有助于我们设计出安全且有效率,具有高度弹性的【设计元素】。所谓Policy,即用来定义一个class 或class template的介面,该介面由下列项目之一或全部组成:内隐型别定义,成员函式和成员变量。
Policies 也被其他人用于traits,不同的是后者比较重视行为而非型别,policies也让人联想到设计范式strategy,只不过policies吃紧于编译期(compile—time bound)。
举个例子,定义一个policy用来生成物件:creator policy是个带有型别T的class template,它必须提供一个名为create的函数给外界使用。这个函数不接受参数,传回一个 T的指针。就语义而言,每当create()被call就必须传回一个指标,指向新生的T物件,至于物件的精确生成模式,留给policy实作品来做订制因子。
现在定义一个可实作出creator policy的class。产生物件的可行办法总体有三种,一即为运算式new,另一种即为malloc加上placement new运算子。此外还可以采用复制的方式。以下为实现代码:
template<class T>
struct OpNewCreator
{
static T* create()
{
return new T;
}
};
template<class T>
struct MallocCreator
{
static T* create()
{
void *buf=malloc(sizeof(T));
return buf?new(buf) T:0;
}
};
template<class T>
struct PrototypeCreator
{
PrototypeCreator(T * pObj=0)
:pPrototype_(pObj)
{ }
T* create()
{
return pPrototype_?pPrototype_->Clone():0;
}
T *GetPrototype()
{
return pPrototype_;
}
void SetPrototype(T *pObj)
{
pPrototype_=pObj;
}
private:
T *pPrototype_;
};
这里有一个重要的概念:policies介面个一般的传统的classes 介面(纯虚函数 classes)不同,它结构比较松散,一位内polices是语法导向而非标记导向。换句话来说creator明确定义的是“怎样的语法构造符合其所规范的class” ,而非“必须实作出哪些函数”。例如creator policy 并没有规范create()必须是static还是virtual,它只是要是class 必须定义出create()。此外creator也只规定create()应该传回一个指向新物件的指针但不是必须的。因此create()也许会传回nullprt 或丢出异常,这些都极为可能。
面对一个policy ,你可以实作出数个policy classes 。它们全都必须遵守policy 所定义的介面。往后你会看到一个例子,使用者选择了一个policy 并应用到较大的结构当中。
先前定义的三个policy classes ,各有不同的实作方式,甚至连介面都不尽相同(第三个policy classes 多了两个函数)。尽管如此,它们全都定义了create(),并传回必要的返回型别。因此它们都符合creator policy。
以下展现的是如何设计一个class 得以利用creator policy,它以复合或继承的方式使用先前所定义的三个classes 之一:
template<class T>
class WidgetManaget:public T
{ ... };
当客户端讲widgetmanager template具现化的时候,必须传进一个他所期望的policy:
typedef WidgetManaget<OpNewCreator<Widget>> MyWidgetMgr;
如同先前的例子所示,policy 的template参数往往都是累赘。使用者每每需要传入template参数给opnewcreator,这很笨拙。一般来说host class 已经知道policy class 所需参数,或者能轻易地推到出来。上述例子中widgetmanager 总是操作widget物件。这样的情况下还要求使用者把widget型别传入opnewcreator,这就显得多余且沉坠。
这时候程式库可以使用 template template参数来描述policies,如下所示:
template <template<class created> class T>
class WidgetManaget:public T<Widget>
{ ... };
应用端现在只需要使用widgetmanager时提供template名称即可:
typedef WidgetManaget<OpNewCreator> MyWidgetMgr;
template<template <class> class T>
class WidgetManaget :public T<Widget>
{
...
void dosomething()
{
Gadget *pG_=T<Gadget>().Create();
...
}
};
为了让应用程序开发人员日子更加轻松,widgetmanager 的作者应该定义一些常用的policies,并且以 template 预设参数 的形式提供最常用的policy:
template <template<class> class T=OpNewCreator>
class WidgetManaget ...
当然,也由于policies的特质,他们不适合用于动态链接和二进位介面,所以本质上policies 和传统介面并不互相竞争。
另外一种使用template template参数 的情况是把template成员函数 用来连接所需的简单型别。也就是说,将policy实作为一般的class,但有一个或数个的template members。
例如,我们可以重新定义先前的creator policy 成为一个 没有template参数的class ,其内提供一个名为create<T>的template函数。如此一来,policy class 看起来如下:
struct OpNewCreator
{
template<class T>
static T *Create()
{
return new T;
}
};