限制类对象生成的数量(三)

    技术2022-05-11  78

    本系列的前两篇文章主要是利用c++语言本身的特点,使我们设计生成的类能够自我保证:从该类实例化的对象数目不会超过某个限定值。其实在我们项目开发中,大多是情况下都是编程者设计的类仅供自己使用,并不需要考虑第三方二次开发使用的情况。如果是这样,我们往往可以使用一些共同的约定来保证对象生成数量的唯一。下面我列举一个我在实际项目开发中的例子。

    开发背景与分析:项目中需要一个专门提供服务功能的函数集合供各个工程模块使用。假如这些服务函数的实现体固定不变,我们完全可以将其存放在一个namespace中;当然也可以采用类包装的方式,把所有函数声明为类的静态成员。但是实际情况中,这些服务函数的实现体需要因为使用环境的不同而发生一些变化。因此,我首先定义出一个接口类,提供各种虚拟的服务函数接口,以便于针对各种不同的使用环境继承实现出不同的函数体。

    ///   <summary> ///  Service接口定义基本的服务功能函数供其它模块使用 ///  同一时刻最多允许有一个服务类实例被注册使用 ///   </summary> class  Service{ public :     ///   <summary>      ///  返回注册的服务类实列     ///  如果没有服务类实例,返回Null       ///   </summary>      ///   <returns> 指向服务类实例的指针 </returns>      static  Service  *  getService()    {         return  pServiec;    }     ///   <summary>      ///  注册服务类实例      ///   </summary>      ///   <param name = "srv"> 指向服务类实例的指针 </param>      static   void   setService(Service  *  srv)    {        pServiec  =  srv;    }     // 多个提供具体服务的纯虚函数      virtual   bool  serviceFunc1()  =   0 ;         // ... private :     static  Service  *  pServiec;};

    这个接口类保存一个静态指针代表当前注册使用的服务类,并通过SET/GET方法来实现服务的加载和访问。注意:这里使用的是静态指针而不是静态类对象。原因是:我们不知道具体的服务实现类究竟是什么。

    // 在不同的环境下,服务的具体内容可能不同,因此需要多个不同的接口实现类 class  ServiceImpOne:  public  Service{ public :    ServiceImpOne(){}         virtual    ~ ServiceImpOne(){}     bool  serviceFunc1()    {         // 函数的实现内容,操作成功返回true,否则返回false     }     // ... }; class  ServiceImpTwo:  public  Service{ public :    ServiceImpTwo(){}         virtual    ~ ServiceImpTwo(){}     bool  serviceFunc1()    {         // 函数的实现内容,操作成功返回true,否则返回false     }     // ... };

    既然是通过指针指向注册的服务对象,就必须要考虑对象的生成和释放,要注意避免内存泄漏的发生。当我们需要注册某个新服务,我们首先需要取消旧的服务。

    Service  *  pS  =  Service::getService(); if  (pS  !=  NULL) {    delete pS;    Service::setService(NULL);}

    注意:指针指向的地址和指针指向的内容不同,因此要在delete指针之后将指针赋为空。否则pS!=NULL的判断就会出问题)然后NEW出相应的服务类对象,并这册保存它

    if  (Service::getService()  ==  NULL) {    ServiceImpTwo  *  pS  =   new  ServiceImpTwo ();    Service::setService(pS);}

    最终,别忘了在程序结束的地方检查并释放函数指针。

    如果在程序的某些地方我们并不希望有任何服务被调用,但是被引用的代码却存在大量服务调用那该怎么办?如果注册服务不为空,则会导致不需要甚至是错误的程序执行;如果注册服务为空。用户使用“if(Service::getService()->serviceFunc1())”必将引发crash。看起来,我们要大面积改动代码。然而,我们这里使用了一个巧妙的方法。从服务接口类继承了一个新的类--ServiceForEnabler。这个类仅仅是为了不改动原有程序的情况下还能够使整个流程enable。这样一来,我们只需在程序的开始处,用一个ServiceForEnabler类对象来注册服务就可以了。

    class  ServiceForEnabler:  public  Service{ public :    ServiceForEnabler(){}         ~ ServiceForEnabler(){}     bool  serviceFunc1()    {         // 直接返回false,代表不成功的调用     }     // ... }

    纵观全局,我们完全保证了服务对象的唯一存在。需要注意的是:这里不是以某一个服务对象贯穿始终,而是多个不同种类服务对象的交替存在。


    最新回复(0)