【设计模式】单例模式

单例模式,或称作单件模式,在整个应用程序运行中只有一个实例。一般用于管理整个进程唯一信息。

如何实现单一实例,

1)定义构造函数为private,禁止外部构造实例。

2)提供static的Instance函数自己提供的实例。之所以定义为static是因为构造函数为private不能通过外部创建的实例访问,只能通过静态类方法调用Singleton::Instance()。而static本身也符合唯一实例的思想。

 

C++实现1:

Singleton.h

#ifndef _SINGLETON_H_

#define _SINGLETON_H_

#include <iostream>



class Singleton

{

public:

    static Singleton* Instance();

private:

    Singleton();

    static Singleton* _instance;

};

#endif
View Code

 

Singleton.cpp

#include "Singleton.h"

#include "stdio.h"



Singleton* Singleton::_instance = NULL;



Singleton* Singleton::Instance()

{

    if (_instance == NULL)

    {

        _instance = new Singleton();

    }

    return _instance;

}



Singleton::Singleton()

{

    //todo something

}
View Code

 

main.cpp

#include "Singleton.h"



int main(int argc,char* argv[])

{

    Singleton* instance = Singleton::Instance();

    //todo something

    return 0;

}
View Code

 

C++实现1问题:以上代码未考虑多线程:

1)线程1线程2先后进入函数走到(几乎是同时)

if (instance == NULL)

2)线程1创建实例退出函数。

3)线程2已经通过instance == NULL的判断,也创建实例。

此时就创建出了2个实例,这明显违背了单一实例的原则。

 

C++实现2:Lazy的实现

Singleton.h

#ifndef _SINGLETON_H_

#define _SINGLETON_H_

#include <iostream>



class Singleton

{

public:

    static Singleton* Instance();

private:

    Singleton();

    static Singleton* _instance;

};

#endif
View Code

 

Singleton.cpp

#include "Singleton.h"

#include "stdio.h"



Singleton* Singleton::_instance = new Singleton();



Singleton* Singleton::Instance()

{

    return _instance;

}



Singleton::Singleton()

{

    //todo something

}
View Code

C++实现2问题:

此种实现在进程启动时就创建出单一实例,后面不判断直接使用。但是如果Singleton存储数据很多,而应用场景很少,比如系统从开始到结束从来被调用过单例,那么这种不管三七二十一就创建的方式对系统资源是一个浪费。

C++实现3:考虑多线程

Singleton.cpp

#include "Singleton.h"

#include "stdio.h"



Singleton* Singleton::_instance = NULL;



Singleton* Singleton::Instance()

{

    if (_instance == NULL)

    {

        mutex; //加锁-伪代码

            if (_instance == NULL)

            {

                _instance = new Singleton();

            }

        mutex; //放锁-伪代码

    }

    return _instance;

}



Singleton::Singleton()

{

    //todo something

}
View Code

为什么要2次判空。

如果一个加锁,一个判空:

1)先加锁后判空,则每次调用Singleton::Instance()都要加锁,而只有第一次创建实例的时候才有可能重复创建实例,以后每次都加锁大大浪费性能。

2)先判空后加锁,与之前没有锁是一样的,达不到防止重入的效果。

 

需要注意的是,访问(增删查)单例类的数据时依然需要加锁。

因为可能存在增删查同时进行的情况,而C++是通过迭代器访问数据,所以例如在线程1读的时候,线程2对数据进行了增删,则线程1的迭代器一经失效,可能因为程序崩溃。

 

你可能感兴趣的:(设计模式)