【C++泛型编程】基于策略(Policy)的类设计


          基于策略(Policy)的类设计是将templates和多重继承组合起来,这样可以产生程序库中的“设计元素”。Policies由templates和多重继承组成。一个class如果使用了policies,就称其为host class,那是一个拥有多个template参数的class template,每一个参数代表一个policy.host class所有的机能都来自policies,运作起来就像是一个聚合了数个policies的容器。

1.什么是Policy?
        它是用来定义一个class或class template的接口,该接口由下面项目的之一或 全部组成:内隐型别定义(如typedef int * pointer)、成员函数和成员变量。Policies有点类似设计模式中的Strategy,只不过policies更注重编译器。而Strategy更注重运行期。

       例子1:定义一个ploicy 用来产生对象,Creator policy是一个带有型别为T的class template,它必须提供一个名为Create()的函数给外界使用,此函数不接受参数,返回一个指向T的指针。下面是三种产生对象的方法即policy:

Policy 1:
template<class T>
struct OpNewCreator
{
static T * Create()
{
return new T;
}
};

Policy 2:
template<class T>
struct MallocCreator
{
static T * Create()
{
void* buf=std::malloc(sizeof(T));
if(!buf) return 0;
else
return new(buf) T;
}
};

Policy 3:

template<class T>
struct PrototypeCreator
{


PrototypeCreator(T* pObj=0):pPrototype_(pObj)
{}
 T * Create()
{
  return ppPrototype_? pPrototype_->Clone():0;


}
T *GetPrototype(){ return pPrototype_;}
void setPrototype(T* pObj){pPrototype_=pObj;}
private:
T * pPrototype_;
};

上面三个policy称为policy classes.这些东西并不是用来单独使用,主要是用于继承或被内含于其他的类。
Creator policy并没有规定Create()必须是static 还是virtual,只要求class必须定义一个Create().你可以定义多个policy class,但是必须遵循统一的接口。


2.利用前面的Creator Policy,怎么样设计一个类?

       我们可以用复合或继承的方式使用前面定义的三个类之一。
例如: 

template<class CreationPolicy>
class WidgetManager:public CreationPolicy
{ };
如果一个类采用了一个或多个policy class,就称其为host或host classes.上面定义的WidgetManager采用了一个policy,称其为host class.Hosts主要负责把上面定义的policies的结构和行为组成一个风复杂的结构和行为。

用户可以将WidgetManager实例化,传进一个用户指定的Policy,如下:
typedef WidgetManager<OpNewCreator<Widget> > MyWidgetPtr;
当一个MyWidgetPtr需要产生一个Widget对象时,它就调用它的policy子对象OpNewCreator<Widget>所提供的Create()函数。WidgetManager是用来选择生成策略(Creation policy)的(基于Policy设计类的宗旨)。


3.怎么样为host class 中的Policy classes的参数设定缺省值?

        在前面可以看到,policy 类的template参数是非常累赘的。使用者每次都需要向Policy 类(如OpNewCreator)传递一个template参数,表示需要创建的对象。如果使用者操作的对象固定,就不需要每次都传递这个参数,可以采用默认的对象来实例化。

a.采用Template Template参数来设定缺省值
 template <template<class Created> class CreationPolicy>
class WidgetManager:public CreationPolicy<Widget>
{.......}
//Created 是CreationPolicy的参数。CreationPolicy 是WidgetManager的参数。上面的Widget已经写入程序库,使用时不需要再传一次参数给policy.可以采用如下方式使用:
typedef WidgetManager<OpNewCreator> MyWidgetMgr;


如果用户想要用WidgetManger的相同策略产生一个Gadget对象,如下:
template<template<class> class CreationPolicy>
class WidgetManager:public CreationPolicy<Widget>
{
void DoSomething()
{
Gadget *pW=CreationPolicy<Gadget>.Create();
}
};

注:为常用的policy提供缺省的参数:
template <template<class> class CreationPolicy=OPNewCreator>
class WidgetManager...;
policies有丰富的型别信息及静态连接等特性,在编译期才把host class和policies结合在一起,所以是建立“设计元素”时的本质性东西。

b.利用Template成员函数来定义policy class。

        我们可以重新定义之前的policy为非template class,该函数内部定义一个template函数,如下:
struct OpNewCreator
{
template<class T>
static T *Create()
{


 return new T;
}
};
这样定义的policy,对旧的编译器比较兼容。这样的policy难以讨论,定义和运用。

4.Policy Classes的析构函数
 
       大部分情况下,host class会以public方式继承某些policies,所以调用者可以将一个host class自动转为一个policy class,并delete 该指针。除非为policy class定义虚析构函数,否则delete一个执行policy class的指针,会产生不可预期的结果。然而如果为policy定一个虚析构函数,会影响policy的静态链接特性,也会影响执行效率。
许多policies并没有数据成员,只纯粹提供一个接口。虚函数的加入会为对象的大学带来额外开销,所以虚函数应该尽量避免。
 一个解决办法是host class 派生policy class时候,采用protected或private继承。但这样会失去丰富的policies特性。
另一个有效的解法是定义一个protected的析构函数。由于是protected,只有派生而得的类才可以摧毁这个policy对象。这样外界就不可能delete一个指向policy class的指针。由于析构函数不是虚函数,不会带来大小或速度上的额外开销。

5.通过不完全具现化获取选择机能
         C++的有趣特性,造就了policies的丰富特性。如果class template有一个成员函数没有用到,它就不会被编译器具体实现出来。编译器不会理会,甚至不进行语法检验。这样就可以让host class有机会并使用policy class的可选特性。如下:

template<template<class> class CreationPolicy>
class WidgetManage:public CreationPolicy<Widget>
{
void SwitchPrototype(Widget *pNewPrototype)
{
CreationPolicy<Widget> &myPolicy=*this;
delete myPolicy.GetPrototype();
myPolicy.SetPrototype(pNewPrototype);
}
};

如果你采用一个定义了SetPrototype()函数的Creator policy来实例化WidgetManager,就可以使用SwitchPrototype()函数。若采用不支持SetPrototype()函数的Creator policy来实例化WidgetManager,就会参数编译错误。如果你采用一个不支持SetPrototype()函数的Creator policy来实例化WidgetManager,如果使用在没有调用SwitchPrototype(),程序是合法的。

6.用Policy class定制结构

       templates的限制之一是你无法定制class的结构,只能定制其行为。然而基于policy 类的设计支持结构方面的定制。
一般像如下定义:

template<class T>
class SmartPtrStorage
{
public:
typedef T *PointerType;
typedef T& ReferenceType;
protected:
PointerType GetPointer(){ return pointee_;}
void SetPointer(PointerType ptr){pointee_=ptr;}
private:
PointerType pointee_;
};

复制 搜索

你可能感兴趣的:(编程,C++,delete,Class,编译器,templates)