c++设计模式之单例模式

来源:互联网 发布:素颜美女知乎 编辑:程序博客网 时间:2024/06/14 05:29
  1. 单例模式概念
    单例模式事比较常用的设计模式之一。一般情况下,我们建立的一些类是属于工具性质的,基本不用存储太多的跟自身有关的数据,在这种情况下,每次都去new一个对象,即增加了开销,也使得代码更加臃肿。其实,我们只需要一个实例对象就可以。如果采用全局或者静态变量的方式,会影响封装性,难以保证别的代码不会对全局变量造成影响,而且这样的代码显的很不优雅。 使用全局对象能够保证方便地访问实例,但是不能保证只声明一个对象——也就是说除了一个全局实例外,仍然能创建相同类的本地实例。
    我们将默认的构造函数声明为私有的,这样就不会被外部所new了,甚至可以将析构函数也声明为私有的,这样就只有自己能够删除自己了。
  2. 单例模式的懒汉模式和饿汉模式
    懒汉模式:就是不到万不得已是不会去实例化类的,也就是说在第一次用到类实例的时候才会去实例化。
    饿汉模式:在单例类定义的时候就实例化了。
    优点和缺点:
    (1)在访问量比较小的时候,采用懒汉模式。以时间换空间。
    (2)因为要进行线程同步,所以在访问量较多的时候,采用饿汉模式,可以实现更好的性能。以空间换时间。
    实现:把构造函数定义为私有的或者保护的,再定义一个类的私有的静态指针,指向这个类的唯一实例,再提供一个公有的静态的方法获取该实例。
  3. 代码实现
    《一》饿汉模式
    (1)饿汉模式实现一
class SiglenTon      //懒汉模式(线程不安全){public:    static SiglenTon *GetInstance()    {        if( ptr == NULL)        {            ptr = new SiglenTon();        }        return ptr;    }private:    SiglenTon()    {        cout<<"SiglenTon()"<<endl;    }    static SiglenTon *ptr;};SiglenTon *SiglenTon::ptr = NULL;int main(){    SiglenTon *ptr = SiglenTon::GetInstance();    return 0;}

该方式实现的单例模式是不安全的,假如有两个线程同时调用GetInstance的时候,同时检测到ptr指针为空,同时创建一个相同的对象,这是错误的。
(2)饿汉模式实现二(加一层互斥锁)

class SigleTon     {public:    static SigleTon *GetInstance()    {        cout<<"static SigleTon *GetInstance()"<<endl;        pthread_mutex_lock(&mutex);           if( ptr == NULL)        {            ptr = new SigleTon();         }        pthread_mutex_unlock(&mutex);        return ptr;    }private:    SigleTon()    {        cout<<"SigleTon()"<<endl;    }    static SigleTon *ptr;};SigleTon *SigleTon::ptr = NULL;

该方式加了一对互斥锁,线程是安全的,但是对于单线程来说,每次都要加锁解锁,效率不高。而且如果每次判断是否为空都需要被锁定,如果有很多线程的话,就会造成大量线程的阻塞。
(3)饿汉模式实现三(两层互斥锁)

class SigleTon   //加双重互斥锁{public:    static SigleTon *GetInstance()    {        cout<<"static SigleTon *GetInstance()"<<endl;        pthread_mutex_lock(&mutex);          if( ptr == NULL)        {            pthread_mutex_lock(&mutex);            ptr = new SigleTon();             pthread_mutex_lock(&mutex);        }        pthread_mutex_unlock(&mutex);        return ptr;    }private:    SigleTon()    {        cout<<"SigleTon()"<<endl;    }    static SigleTon *ptr;};SigleTon *SigleTon::ptr = NULL;

(4)饿汉模式实现四(用一个静态内部变量实现懒汉模式)
在Instance函数里定义一个静态的实例,也可以保证拥有唯一实例,在返回时只需要返回其指针就可以了。推荐这种实现方法,真得非常简单。

class SiglenTon   {public:    static SiglenTon *Instance()    {        cout<<"static SiglenTon Instance()"<<endl;        pthread_mutex_lock(&mutex);        static SiglenTon msigleton;        pthread_mutex_lock(&mutex);        return &msigleton;    }private:    SiglenTon()    {        cout<<"SiglenTon()"<<endl;    }    static SiglenTon *ptr;};SiglenTon *SiglenTon::ptr = NULL;

《二》懒汉模式
在类外初始化指针的时候就创建一个对象。懒汉模式是线程安全的,不用加互斥锁,因为在当类定义的时候定义了一个对象,对类进行了初始化。后面不管哪个线程调用Instance函数,都只不过是返回了一个对象的指针而已。

class SigleTon{public:    static SigleTon *GetInstance()    {        cout<<"static SigleTon *GetInstance()"<<endl;        if( ptr == NULL)        {            return ptr;        }    }private:    SigleTon()    {        cout<<"SigleTon()"<<endl;    }    static SigleTon *ptr;};SigleTon *SigleTon::ptr  = new SigleTon();
原创粉丝点击