[设计模式]创建模式-单例(C++描述)

[设计模式]创建模式-单例(C++描述)

second60 20180425

单例是23种设计模式中最常用的,没有之一。

 

1. 什么是单例?

一句话,单例就是一个全局变量(对象)。在整个程序生命周期,只有一个实例。

单例的实现很简单。

 

2. 单例结构图

 

3. 简单单例

C++中,用static 函数和static变量来实现或用模来来继承。

 

3.1代码一(static 成员变量版)

class Singleton

{

public:

static Singleton* instance()

{

if(_instance == NULL) _instance = new Singleton();

return _instance;

}

private:

static Singleton* _instance;

Singleton(){} // 不能被外面实例化

~Singleton(){}

};

Singleton* Singleton::_instance() = 0;

使用:

Singleton::instance();

 

3.2代码二(指针版)

class Singleton

{

public:

static Singleton* instance()

{

static Singleton* _instance = NULL; // 指针

if(_instance) _instance = new Singleton();

return _instance;

}

private:

Singleton(){}

~Singleton(){}

};

使用:

Singleton::instance();

 

 

3.3代码三(不用指针版)

class Singleton

{

public:

static Singleton* instance()

{

static Singleton _instance; // 非指针

return &_instance;

}

private:

Singleton(){}

~Singleton(){}

};

 

使用:

Singleton::instance();

 

3.4 代码四(模版)

template <class T>  

class Singleton

{  

private:static T* m_pInstance;  

    Singleton(const Singleton& src){}  

    Singleton &operator=(const Singleton& src){};  

protected:  

    //使继承者无法public构造函数和析构函数  

    Singleton(){}  

    ~Singleton(){}

public:  

    static T* getInstance()  

    {  

        if (m_pInstance == NULL)  //判断是否第一次调用  

            m_pInstance = new T();  

        return m_pInstance;  

    }  

};  

template <class T>  

T* Singleton<T>::m_pInstance = NULL;

 

使用方法:

class A : public Singleton<A>{};


上面给出四种简单单例,很多种吧~~你是否还能想到更多的。使用看个人喜欢,我比较喜欢使用第二三种,因为化码量会少很多。第四种模版类,在大系统架构时用的比较多。

 

网上很多说法:

饥饿模式的单例:程序启动时就实例化

懒汉模式的单例:调用时再实例化单例

 

3.5 优缺点

 

优点:都提供了全局唯一的实现,实现了全局类。

缺点:上面四种只是实例了单了,但是并没有处理多线程中的问题,是线程不安全的,多个线程调用,初始化对象可能会调用多次

 

4 线程安全单例

怎么做到线程安全呢?当然是加锁了,所以又提出了双重检查锁机制,即在创建单例对象时,两次判断加锁。

 

4.1 代码一(static变量)

class Singleton

{

private:

    static Singleton* m_instance;

    Singleton(){}

public:

    static Singleton* getInstance();

};

 

Singleton* Singleton::getInstance()

{

    if(NULL == m_instance)

    {

        Lock();

        if(NULL == m_instance)

        {

            m_instance = new Singleton;

        }

        UnLock();

    }

    return m_instance;

}

 

4.2代码二

class Singleton

{

private:

Singleton(){}

public:

    static Singleton* instance()

    {

        Lock();

        static SingletonInside instance;

        UnLock();

        return instance;

    }

};

 

4.3 代码三(饿汉模式)

class Singleton

{

private:

    static const Singleton* m_instance;

    Singleton(){}

public:

    static const Singleton* getInstance()

    {

        return m_instance;

    }

};

 

const Singleton* Singleton::m_instance = new Singleton;

 

4.4 线程安全单例总结

关于线程安全,其实最主要是因为创建时,多个线程可能会同时实例化类,所以采用了锁机制,在第一个线程进入实例化时,加锁,创建后释放。

所以采用饿汉模式,是不会有上面的创建问题,因为饿汉模式在程序启动时已创建,所以在性能要求比较高时,避免频繁加锁,造成开销大。

 

当然,如果是关系到单例类内部成员的同步问题,还是需要加锁滴。因为数据才能同步。不会两个线程拿到单例后,交叉更改数据造成不同步。

 

 

5 运用场景

单例是运用的最广泛的设计模式,说说运用的场景:

a) 公共配置,如果整个程序只有一份的配置,通常都是单例

b) 工具类,如果是一个工具类,通常也是用单例或static方法

c) 公共数据,整个程序只有一份数据,通常用单例来维护

d) 全局变量

e) 所有想程序生命周期只有一个实例的类

 

6 总结

单例,平时用的最多了,不总结还不知道,一总结吓一跳,其实单例的实现方法很多,如果在单线程中,是不用考虑线程安全的;但如果是在多线程中,需要考虑下多线程安全的问题,如双重检查机制或饿汉模式,看运用场景。

快下班了,今天又贡献了一篇,开开心心分享!

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值