标签:
引言
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。单实例模式的UML图如下所示。
一个类只能产生一个对象,该怎么实现呢?我们知道,可以通过类定义对象创建实例,或者通过new关键字产生对象;这个该怎么控制?
创建对象时,都会根据输入的参数调用相应的构造函数,如果我们把构造函数设置为private私有访问权限不就不可以创建对象了吗?
还有个问题:那我总要创建一个对象啊,单实例啊,不是无实例!咋办?有办法!可以定义一个公有的函数GetInstance()用于返回对象,这样就能创建辣!
这又出现问题了,那这样做和将构造函数公有化有什么区别?你还是可以通过GetInstance()函数来创建多个对象...
咋办?能不能只创建一次,设置个标志位?再次创建的时候判断一下?那得保证创建的这个变量的生存期不随对象的创建和销毁而变化,有了! 用static关键字声明吧。
因为GetInstance()的返回类型为对应的类,所以需要定义一个含有该类的静态私有对象。
举例说明一下:
皇帝一般来说,一个时期只存在一个,下面用大臣参拜皇帝的例子来说明单实例模式。CEmperor代表皇帝类,大臣在主函数中参拜皇帝。
1 /* 2 Time:2016-9-25 18:26:39 3 Author:CodingMengmeng 4 Description:Singleton. 5 */ 6 #include <iostream> 7 #include <tchar.h> 8 using namespace std; 9 10 class CEmperor{ 11 private: 12 CEmperor();//注意:构造函数私有 13 virtual ~CEmperor(); 14 static CEmperor* instance;//唯一实例 15 16 public: 17 static CEmperor* GetInstance();//工厂方法(用来获得实例) 18 static void emperorSay(void);//类中其它方法,尽量是static 19 20 }; 21 22 CEmperor::CEmperor() 23 { 24 //世俗和道德约束你,目的就是不希望产生第二个皇帝 25 cout << "CEmperor Constructor" << endl; 26 } 27 28 CEmperor::~CEmperor() 29 { 30 if (instance != NULL) 31 delete instance; 32 } 33 34 //静态成员变量必须在类外初始化 35 CEmperor* CEmperor::instance = NULL; 36 37 CEmperor* CEmperor::GetInstance() 38 { 39 if (instance == NULL) //如果未创建过,则new一个出来,如果new过了,则直接返回 40 instance = new CEmperor(); 41 return instance; 42 } 43 44 void CEmperor::emperorSay() 45 { 46 cout << "我就是皇帝某某某...." << endl; 47 } 48 49 class CMinister{ 50 51 }; 52 53 int _tmain(int argc, _TCHAR* argv[]) 54 { 55 for (int day = 0; day < 3; day++) 56 { 57 CEmperor* emperor = CEmperor::GetInstance();//当GetInstance()为static时,才能保证实例由类本身来创建,否则一个非static成员函数必须与特定对象搭配才能调用 58 emperor->emperorSay(); 59 } 60 61 //三天见的皇帝都是同一个人。 62 return 0; 63 }
运行结果:
分析:
当第一次调用GetInstance()时,instance为NULL,所以会执行instance=new Emperor();把这个新建的实例保存到静态成员instance,并返回这个指针。
第二次到第N次调用GetInstance()时,由于instance不为空,所以会直接返回instance。也就是第一次调用GetInstance创建的那个实例,这样就实现了单实例。
要点
显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
从具体实现角度来说,就是以下三点:一是单例模式的类只提供私有的构造函数,二是类定义中含有一个该类的静态私有对象,三是该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。上面的例子中,
static CEmperor* instance;
即表示要点二:类定义中含有一个该类的静态私有对象;
static CEmperor* GetInstance();
即表示要点三:该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。
单实例的应用
1、单实例模式的优点
2、单实例模式的缺点
3、单实例模式的使用场景
在一个系统中,要求一个类有且仅有一个对象,如果出现多个对象就会出现“不良反应”时,则可以采用单例模式,具体的场景如下:
4、单实例模式的注意事项
在高并发情况下,请注意单例模式的线程同步问题。
标签:
原文地址:http://www.cnblogs.com/codingmengmeng/p/5906583.html