一、单例模式的定义
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
二、单例模式的使用场景
1、日志系统;
2、windows的任务管理器;
3、网站的计数器;
4、操作系统的文件系统;
主要用于资源共享和控制资源两方面,从而可以有效地避免由于资源操作时导致的性能损耗以及通信损耗。
三、单例模式的实现思想
一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名 称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们 还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。
四、单例模式的优缺点
1、优点:解决资源,控制受控区域;
2、缺点:
1)多线程下,可能产生线程安全问题,同时可能产生多个实例,可以使用双重加锁解决,但是会降低效率;
2)难扩展,并且易违背单一职责原则。
注:线程安全,不管多个线程是怎样的执行顺序和优先级,或是wait,sleep等控制方式,如果一个类在多线程访问下运转一切正常,并且访问类不需要进行额外的同步处理或者协调,那么我们就认为它是线程安全的。 线程安全的类应当封装了所有必要的同步操作,调用者无需额外的同步。
五、单例模式的多种代码示例
1、适用除多线程状况下
class Singleton{
public:
static Singleton *GetInstance()
{
if (m_Instance == NULL )
{
m_Instance = new Singleton ();
}
return m_Instance;
}
static void DestoryInstance()
{
if (m_Instance != NULL )
{
delete m_Instance;
m_Instance = NULL ;
}
}
private:
Singleton(){}
static Singleton *m_Instance;
};
Singleton *Singleton ::m_Instance = NULL;
int main(int argc , char *argv []){
Singleton *singleton= Singleton ::GetInstance();
Singleton ::DestoryInstance();
return 0;
}
2、懒汉式,利用双重校验机制,适用除大数据并发场景
class Singleton{
public:
static Singleton *GetInstance()
{
if (m_Instance == NULL )
{
Lock(); // 使用其它库的Lock,eg:Boost
if (m_Instance == NULL )
{
m_Instance = new Singleton ();
}
UnLock();
}
return m_Instance;
}
static void DestoryInstance()
{
if (m_Instance != NULL )
{
delete m_Instance;
m_Instance = NULL ;
}
}
private:
Singleton(){}
static Singleton *m_Instance;
};
Singleton *Singleton ::m_Instance = NULL;
int main(int argc , char *argv []){
Singleton *singleton= Singleton ::GetInstance();
Singleton ::DestoryInstance();
return 0;
}
3、饿汉式方法,适用除多线程
class Singleton
{
private:
Singleton (){}
static Singleton *m_pInstance;
class ReleGC //在析构函数中删除Singleton 的实例
{
public:
~ReleGC()
{
if(Singleton ::m_Instance)
delete Singleton ::m_Instance;
}
};
static ReleGC releGC; //静态成员变量,程序结束时,系统会自动调用它的析构函数
public:
static Singleton * GetInstance()
{
if(m_pInstance == NULL) //判断是否第一次调用
m_Instance = new Singleton ();
return m_Instance;
}
};
Singleton *Singleton::m_Instance = new Singleton();
Singleton::ReleGC Singleton::releGC;
int main(int argc , char *argv []){
Singleton *singleton = Singleton ::GetInstance();
return 0;
}
所谓“懒汉式”与“饿汉式”的区别,是在与建立单例对象的时间的不同。“懒汉式”是在你真正用到的时候才去建这个单例对象,“饿汉式”是在不管你用不用的上,一开始就建立这个单例对象。
对于选择哪种方式实现单例模式是最正确的,并没有完全统一的说法,应该根据不同的应用场景进行不同的选择才是正确的。