linux C++ 设计模式:单例、单例继承详解

一、单例

1.1. 意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

 

1.2. 动机

如何保证一个类只有一个实例,并且这个实例易于被访问呢?

如希望系统中只有一个脱机打印机实例,只有一个访问配置文件的实例时。

如果使用全局变量,将使得一个对象可以被访问,但它不能防止你实例化多个对象。

 

一个更好的办法是:

让类自身负责保存它的唯一实例。

这个类可以保证没有其他实例可以被创建(通过截取创建新对象的请求),

并且它可以提供一个访问该实例的方法。

 

.1.3. 适用性

在下面的情况下可以使用Singleton模式

• 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

• 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个

扩展的实例时。

 

1.4 解析

. 在面向对象开发中,对象与对象之间的成员变量是相互独立的。

要想共用数据,则需要使用静态成员和静态方法。

. 只要在类中声明静态成员变量,即使不定义对象,也可以为静态成员变量分配空间,

进而可以使用静态成员变量。

(因为静态成员变量在对象创建之前就已经被分配了内存空间)

. 静态成员变量虽然在类中,但它并不是随对象的建立而分配空间的,

也不是随对象的撤销而释放(一般的成员在对象建立时会分配空间,在对象撤销时会释放)。

静态成员变量是在程序编译时分配空间,而在程序结束时释放空间。

. 静态成员的定义和声明要加个关键static。

静态成员可以通过双冒号来使用,即<类名>::<静态成员名>。

. 初始化静态成员变量要在类的外面进行。

初始化的格式如下:数据类型  类名::静态成员变量名 = 初值;

. 不能用参数初始化表,对静态成员变量进行初始化。

. 既可以通过类名来对静态成员变量进行引用,也可以通过对象名来对静态成员变量进行引用。

. 普通成员函数和静态成员函数的区别是:

普通成员函数在参数传递时编译器会隐藏地传递一个this指针.

通过this指针来确定调用类产生的哪个对象;

但是静态成员函数没有this指针,不知道应该访问哪个对象中的数据,

所以在程序中不可以用静态成员函数访问类中的普通变量.

 

1.5. 参与者

• Singleton

— 定义一个Instance操作,允许客户访问它的唯一实例。

Instance是一个类操作,即C + +中的一个静态成员函数。

— 可能负责创建它自己的唯一实例。

1.6. 协作

• 客户只能通过S i n g l e t o n的I n s t a n c e操作访问一个S i n g l e t o n的实例。

 

1.7 示例代码

1.7.1 《设计模式》中示例代码:

Sinleton类定义如下:

class Singleton {

public:

static Singleton* Instance();

protected:

Singleton();

private:

static Singleton* _instance;

};

 

Singleton类的实现:

Singleton* Singleton::_instance =0;

Singleton* Singleton::Instance() {

if (_instance == 0){

_instance = new Singleton;

}

return _instance;

}

 

1.7.2 线程安全的代码

一个用于加载和解析配置文件的类,Configuration,用单例实现 。

Configuration类定义如下:

class CConfiguration{
public:
    ~CConfiguration(){};
    static CConfiguration *get_instance();

private:
    static CConfiguration* _instance;
    CConfiguration() {
        _instance = NULL; // 即this->_instance = NULL;
    };


    /* Singleton garbage */
    class SingletonGarbo {
    public:
        ~SingletonGarbo() {
            if (CConfiguration::_instance) {
                delete CConfiguration::_instance;
            }
        }
    };

    static SingletonGarbo _garbo;
};



Configuration的实现如下:
CConfiguration::SingletonGarbo CConfiguration::_garbo;
CConfiguration *CConfiguration::_instance = NULL;



CConfiguration *CConfiguration::get_instance() {
    //静态成员函数第一次被调用时,满足该条件
    if (NULL == _instance) {
        //先是创建了一个实例对象,然后把实例对象的地址给了指向该实例对象的指针
        _instance = new CConfiguration();
    }
    return _instance;
}

解析:

静态成员函数访问构造函数

https://www.cnblogs.com/ShaneZhang/p/3722519.html

 

 

1.7.3 更多的实现

《C++实现单例的5种方法总结》

http://blog.csdn.net/zztan/article/details/54691809

 

二、单例的继承

2.1 原理

单例的意图,是保证一个类仅有一个实例,并提供一个访问它的全局访问点。

那在继承时,使用的也是同样的该接口

 

2.2 示例代码

// gearman_worker_factory.h
class CGearmanWorkerFactory{
public:
    static CGearmanWorkerFactory* get_instance(const char* name);
    ~CGearmanWorkerFactory(){};

protected:
    CGearmanWorkerFactory() {
        _instance = NULL;
    }

private:
    static CGearmanWorkerFactory* _instance;

    // Singleton garbage
    class SingletonGarbo {
    public:
        ~SingletonGarbo() {
            if (CGearmanWorkerFactory::_instance) {
                delete CGearmanWorkerFactory::_instance;
            }
        }
    };

    static SingletonGarbo _garbo;
};



// gearman_worker_factory.cpp
CGearmanWorkerFactory::SingletonGarbo CGearmanWorkerFactory::_garbo;
CGearmanWorkerFactory* CGearmanWorkerFactory::_instance = NULL;

CGearmanWorkerFactory* CGearmanWorkerFactory::get_instance(const char *name){
    if (NULL == _instance) {
        if (strcmp(name, "record") == 0) {
            RecordFactory* ins_record = CRecordFactory::get_instance();
            _instance = dynamic_cast<CRecordFactory*>(ins_record);
        } else if (strcmp(name, "player") == 0){
            CPlayerFactory* ins_player = CPlayerFactory::get_instance();
            _instance = dynamic_cast<CPlayerFactory*>(ins_player);
        }
    }

// record_factory.h
class CRecordFactory: public CGearmanWorkerFactory {
public:
    static CRecordFactory* get_instance();
    ~CRecordFactory(){};

private:
    static CRecordFactory* _instance;
    CRecordFactory(){
        _instance = NULL;
    }

    // Singleton garbage
    class SingletonGarbo {
    public:
        ~SingletonGarbo() {
            if (CRecordFactory::_instance) {
                delete CRecordFactory::_instance;
            }
        }
    };
    static SingletonGarbo _garbo;
}



// record_factory.cpp
CRecordFactory* CRecordFactory::_instance = NULL;

CRecordFactory* CRecordFactory::get_instance(){
    if (NULL == _instance) {
        _instance = new CRecordFactory();
    }

    return _instance;
}



// player_factory.h

// player_factory.cpp

//和record_factory一样;

 

三、勘误

3.1 网上的一个解法

https://www.cnblogs.com/faith0217/articles/4083484.html

他在这里用到了一个友元,实际上破坏了单例的意图:

是保证一个类仅有一个实例,并提供一个访问它的全局访问点。

且实际应用时,通过new和get_instance获得的是两个不同的对象指针,运行时将会出错;

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北雨南萍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值