C++设计模式之单例模式(二)

简介

  单例模式(Singleton Pattern,又称单件模式),是一种使用非常广泛的设计模式。其目的是为了保证一个类之某程序中有且只有一个实例,并且提供了一个全局访问的接口,即该实例是被程序共享的。
  单例模式的类图:

Singleton -$Singleton *unique_instance$ -Singleton() +$Singleton* getInstance()

  单例模式的特征:

  1. 私有化它的构造函数,以防止外界创建该类的实例;
  2. 使用类的私有静态变量指针指向类的唯一实例;
  3. 使用一个共有的静态方法获取该类的实例。

单例模式实现的方式

1.饿汉式

  何为饿汉式?就是在正常情况下,程序进行初始化的时候,已将该对象实例化。后续使用的时候不需要进行初始化。

class Singleton
{
private:
	static Singleton* instance;
private:
	Singleton() {};
	~Singleton() {};
	Singleton(const Singleton&);
	Singleton& operator=(const Singleton&);
public:
	static Singleton* getInstance() 
    {
		return instance;
	}
};

//initialize defaultly
Singleton* Singleton::instance = new Singleton();

  饿汉式的单例对象实在程序的main函数之前进行初始化的,所以是不存在线程安全问题的。

2.懒汉式

  何为懒汉式?就是在正常情况下,我需要用到该对象的时候,才会去初始化该对象(即,在第一次使用的时候被初始化)。

class Singleton
{
private:
	static Singleton* instance;
private:
	Singleton() {};
	~Singleton() {};
	Singleton(const Singleton&);
	Singleton& operator=(const Singleton&);
public:
	static Singleton* getInstance() 
    {
		if(instance == NULL) 
			instance = new Singleton();
		return instance;
	}
};

// init static member
Singleton* Singleton::instance = NULL;

3.线程安全方式

  在使用多线程的时候,若用到懒汉式的方式去实现单例,那么会出现线程不安全的情况;假设有两个线程,pthread_1刚判断完 intance 为NULL 为真,准备创建实例的时候,切换到了pthread_2, 此时pthread_2也判断intance为NULL为真,创建了一个实例,再切回pthread_1的时候继续创建一个实例返回,那么此时就不再满足单例模式的要求了, 既然这样,是因为多线程访问出的问题,那我们就来加把锁,使得线程同步;

class Singleton
{
private:
	static Singleton* instance;	
	static pthread_mutex_t mutex;
private:
	Singleton() {};
	~Singleton() {};
	Singleton(const Singleton&);
	Singleton& operator=(const Singleton&);
public:
	static Singleton* getInstance() 
    {
    	if (NULL == instance ){
            pthread_mutex_lock(&mutex)
		    if(instance == NULL) 
			    instance = new Singleton();
            pthread_mutex_unlock(&mutex)
        }
		return instance;
	}
};


pthread_mutex_t singleton::mutex;
// init static member
Singleton* Singleton::instance = NULL;

4.泛编方式

template <typename T>
class Singleton {

public:
    static T* GetInstance(){
        static std::once_flag s_flag;
        std::call_once(s_flag, [&](){
            singleton_ptr.reset(new T);
        });

        return singleton_ptr.get();
    }

protected:
    Singleton(){};
    ~Singleton(){};

private:
    static std::shared_ptr<T> singleton_ptr;

    Singleton(const Singleton&) = delete;
    Singleton&operator=(const Singleton&) = delete;
}; // end singleton

template<typename T> std::shared_ptr<T> Singleton<T>::singleton_ptr;

  该方式里面用到了一些C11中的知识,例如std::shared_ptr,std::once_flag,std::call_once;这种方式的优势在于,当某一程序中需要多个不同类型的单例对象的时候,不需要再实现相应的方法,直接继承该类就可以了。如下所示:

class TestClass: public Singleton<TestClass> {
    public:
        TestClass();
        ~TestClass();
    };

使用场合

  1. 系统只需要一个实例对象,或者考虑到资源消耗的太大而只允许创建一个对象;
  2. 客户调用类的单个实例只允许使用一个公共访问点,除了该访问点之外不允许通过其它方式访问该实例 (就是共有的静态方法).

猜你喜欢

转载自blog.csdn.net/CFH1021/article/details/108906561
今日推荐