本系列的前两篇文章主要是利用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,代表不成功的调用 } // ... }纵观全局,我们完全保证了服务对象的唯一存在。需要注意的是:这里不是以某一个服务对象贯穿始终,而是多个不同种类服务对象的交替存在。
