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

来源:互联网 发布:极乐宿舍使用软件 编辑:程序博客网 时间:2024/06/07 12:40

          基于策略(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;elsereturn 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_;};

复制搜索
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 北方黄胡蜂蜇了怎么办? 猫咪被蜜蜂蛰了怎么办 猫被蜜蜂蛰了怎么办 猫被马蜂蛰了怎么办 被地雷蜂蛰了怎么办 被葫芦蜂蛰了怎么办 嘴巴被蜜蜂蛰了怎么办 被蜜蜂蜇伤了怎么办 婴儿被蜜蜂蜇了怎么办 婴儿被黄蜂蛰了怎么办 蜜蜂在石头缝里怎么办 中蜂蜂王不产卵怎么办 冲电器充电变慢怎么办 摇号审核通过后怎么办 京东白条开不了怎么办 得了病心里压力大怎么办 电视家看直播卡怎么办 日上提货单丢了怎么办 想直飞香港l签怎么办 u盘识别不出来怎么办 卫生间下水道有小飞虫怎么办 橙光一直闪退怎么办 若白回来了,长安怎么办 没了你以后我该怎么办 玩cf的时候闪退怎么办 婴儿嗓子哭哑了怎么办 宝宝嗓子哭哑了怎么办 小孩嗓子哭哑了怎么办 孩子嗓子哭哑了怎么办 月经来了晚上漏怎么办 在学校月经漏了怎么办 月经来了血下不来怎么办 想让月经快点来怎么办 孩子来月经不规律怎么办 一个月来2次月经怎么办 14岁月经不规律怎么办 不是经期内裤有黑色血怎么办 月经量多血块多怎么办 网友见面没上她怎么办 拔完智齿老流血怎么办 学车教练不教怎么办