妙空

空妙
随笔 - 0, 文章 - 11, 评论 - 0, 引用 - 0
数据加载中……

Design Patterns学习笔记05:Singleton

一、概述
在很多情况下,我们的系统只允许某个类有一个或指定个数的实例,如一般的应用系统往往有且仅有一个log文件操作类实例,或者,整个系统仅有一个等待事务队列等(注意:Singleton不是用来解决整个应用程序仅有一个实例这样的问题的),在这些情况下可以考虑使用Singleton模式。
Singleton(单件)模式用于保证一个类仅有一个实例,并提供一个访问该实例的全局访问点。(GoF: Ensure a class only has one instance, and provide a global point of access to it.

二、结构
Singleton典型的结构如下图所示:

1:Singleton模式的类图示意

三、应用
Singleton模式从概念上讲应该是所有模式中最简单的,它的目的很简单:限制我们创建实例的个数,Only one is permited。不过,该模式也可以扩展到允许指定数量个实例的情况。
一眼看去,Singleton似乎有些像全局对象。但是实际上,并不能用全局对象代替Singleton模式,这是因为:其一,有些编程语言例如Java、C#等,根本就不支持全局变量。其二,全局对象的方法并不能阻止人们将一个类实例化多次:除了类的全局实例外,开发人员仍然可以通过类的构造函数创建类的多个局部实例。而Singleton模式则通过从根本上控制类的创建,将“保证只有一个实例”这个任务交给了类本身,开发人员不可能再有其它途径得到类的多个实例。这一点是全局对象方法与Singleton模式的根本区别。

四、优缺点
Singleton模式是作为"全局变量"的替代品出现的,所以它具有全局变量的特点:全局可见;它也具有全局变量不具备的性质:同类型的对象实例只可能有一个。对于全局变量“贯穿应用程序的整个生命期”的特性,对于Singleton,视具体的实现方法,并不一定成立。

五、举例
实现该模式最简便的方法就是:采用static变量,并将类的构造函数、拷贝构造函数、赋值函数声明为private或者protected,同时提供public的实例创建/访问函数。
示例代码如下:

最后,需要注意的是,在C++中,单件对象的释放是个比较麻烦的事情,在上面的第一个示例中,由于没有释放单件对象,实际上是存在内存泄漏的,在释放单件对象的问题上,我们有以下几种选择:
1
、在程序退出时由上层应用负责delete,比如在MFC程序中,在ExitInstance中逐一检查SingletonFactory的静态map对象所保存的Singleton;
2
、在Singleton内部采用静态auto_ptr来封装Singleton对象,按此方法修改后的示例1如下所示:


/**********************************START****************************************
实现该模式最简便的方法就是:采用static变量,并将类的构造函数、拷贝构造函数、赋值
函数声明为private或者protected,同时提供public的实例创建/访问函数。

第二个例子是用auto_ptr只能指针管理内存的动态分配
**********************************END***************************************
*/

#include 
<assert.h>
#include 
<iostream>
using namespace std;

class Singleton
{
public:
    
static Singleton* Instance() {
        
if (pInstance == NULL)
            pInstance 
= new Singleton();
        
return pInstance;
    }
protected:
    Singleton() {}
private:
    
static Singleton* pInstance;
    Singleton(
const Singleton&) ;
    Singleton
& operator=(const Singleton&) ;
};

Singleton
* Singleton::pInstance = NULL;

int main()
{
    
//Singleton instance;                    // Canot access protected constructor
    
//Singleton* pInstance = new Singleton;    // Error
    
//Singleton instance = Singleton::Instance();    // Error
    Singleton* pInstance1 = Singleton::Instance(); // Good
    Singleton* pInstance2 = Singleton::Instance();

    
//cout.setf(ios::hex, ios::basefield);
    cout << "pInstance1 = " << pInstance1 << endl;
    cout 
<< "pInstance2 = " << pInstance2 << endl;
    
//cout.setf(ios::dec, ios::basefield);
    assert(pInstance1 == pInstance2);
    
    
return 0;
}

/********************************OUTPUT**************************************
pInstance1 = 00384F98
pInstance2 = 00384F98
Press any key to continue . . .
结果里面显示虽然实例化了两次,但是内容一样,因此只有一个类对象产生
**********************************END***************************************
*/



#include 
<assert.h>
#include 
<iostream>
#include 
<memory>
using namespace std;

class Singleton
{
public:
    
static Singleton* Instance() {
        
if (instance.get() == NULL)
        {
            instance.reset(
new Singleton());
        }
        
return instance.get();
    }
protected:
    Singleton() {}
private:
    
static auto_ptr<Singleton> instance;
    Singleton(
const Singleton&) ;
    Singleton
& operator=(const Singleton&) ;
};

auto_ptr
<Singleton> Singleton::instance = auto_ptr<Singleton>(NULL);

int main()
{
    Singleton
* pInstance1 = Singleton::Instance(); // Good
    Singleton* pInstance2 = Singleton::Instance();


    cout 
<< "pInstance1 = " << pInstance1 << endl;
    cout 
<< "pInstance2 = " << pInstance2 << endl;

    
assert(pInstance1 == pInstance2);
    
    
return 0;
}

/********************************OUTPUT**************************************
pInstance1 = 00384F98
pInstance2 = 00384F98
Press any key to continue . . .
结果里面显示虽然实例化了两次,但是内容一样,因此只有一个类对象产生
**********************************END***************************************
*/


posted on 2008-01-08 11:26 龙人 阅读(22) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航:   博客园   博客园最新博文   博问   管理