最近学习了下《head first设计模式》,先对单例模式做个简单的总结。
为什么不用全局变量?
单例模式用一句话概括就是只产生一个对象,那为啥不用全局变量来代替单例模式呢?
全局变量是程序在一开始就创建好对象,如果这个对象非常耗费资源,程序的执行又用不到它,那就太浪费了。而单例可以在需要它的时候再创建它。
使用场景
线程池,缓存,处理偏好设置,注册表的对象,日志对象,充当打印机、显卡等设备的驱动程序的对象。
实现
一句话,构造函数为私有就可以实现了。
看下c++中的一个简单实现:
singleton.h
//2013-4-10 10:07
//单例设计模式
class MySingleton
{
public:
~MySingleton();
static MySingleton* GetInstance();
private:
MySingleton();
};
singleton.cpp
#include "singleton.h"
MySingleton::~MySingleton()
{
}
MySingleton::MySingleton()
{
}
MySingleton* MySingleton::GetInstance()
{
static MySingleton* pInstance = new MySingleton();
return pInstance;
}
问题1
实现很简单,这样就保证只会产生一个实例了。但是这样会产生一个问题。什么问题呢???
可以写个客户端的代码验证:
int main(int argc,char* argv[])
{
MySingleton* pMySingleton = MySingleton::GetInstance();
MySingleton* pMySingleton1 = MySingleton::GetInstance();
delete pMySingleton;
delete pMySingleton1;
return 0;
}
是的,释放内存就会出问题了。
这样不得不考虑重新实现了,怎么才能保证释放一次并且自动释放?
有一个技巧:
参考了http://www.cnblogs.com/binxindoudou/p/3261082.html
我的实现如下:
//singleton.h
#pragma once
#include <iostream>
using namespace std;
class MySingleton
{
private:
static MySingleton* pInstance;
public:
static MySingleton* GetInstance();
class SingletonGarbo // 它的唯一工作就是在析构函数中删除CSingleton的实例
{
public:
~SingletonGarbo()
{
//测试用
cout<<"SingletonGarbo::~SingletonGarbo()"<<endl;
if (0 != MySingleton::pInstance)
{
delete MySingleton::pInstance;
MySingleton::pInstance = 0;
}
}
};
private:
MySingleton();
~MySingleton();//防止在不合适的地方释放了
};
//singleton.cpp
#include "singleton.h"
MySingleton* MySingleton::pInstance = 0;
MySingleton::SingletonGarbo garbo;
MySingleton::~MySingleton()
{
}
MySingleton::MySingleton()
{
}
MySingleton* MySingleton::GetInstance()
{
if ( pInstance == 0)
{
pInstance = new MySingleton();
}
return pInstance;
}
这样就保证在程序结束的时候释放单例对象了。应该还有别的比较好的实现,类中类总感觉不好,还没想到。如果有了补充。
问题2
还会不会有问题呢?
多线程。是的,GetInstance()方法中多线程可能会出问题。
if ( pInstance == 0)
//线程1访问,刚好到此时间片轮换
{
pInstance = new MySingleton();
}
return pInstance;
//线程2开始执行
if ( pInstance == 0)
{
pInstance = new MySingleton();
}
return pInstance;
这样就产生两个对象了。
解决办法是同步即可,伪代码:
MySingleton* MySingleton::GetInstance()
{
lock();
if ( pInstance == 0)
{
pInstance = new MySingleton();
}
unlock();
return pInstance;
}
但是这样效率太低了,每次获取对象的时候都要同步,一个同步会使效率低100倍。
可以第一次进行同步,下次就不用了。伪代码:
MySingleton* MySingleton::GetInstance()
{
if ( pInstance == 0)
{
lock();
if ( pInstance == 0)
{
pInstance = new MySingleton();
}
unlock();}
return pInstance;
}
可以继承吗?
参考两篇文章:
1
[C++]通过模板类巧妙实现单件模式的继承
http://hi.baidu.com/gookings/item/68f471ca0da60a17b67a24a2
2,
可以继承的C++ Singleton基类
http://www.gocalf.com/blog/cpp-singleton.html
3
Singleton模式是常用的设计模式之一,但是要实现一个真正实用的设计模式却也不是件容易的事情。
http://www.cppblog.com/dyj057/archive/2005/09/20/346.html