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

来源:互联网 发布:淘宝店铺首页滚动大图 编辑:程序博客网 时间:2024/06/06 06:52

本系列的前两篇文章主要是利用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,代表不成功的调用
    }
    
//...
}

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

原创粉丝点击