设计模式之单例模式(c++)
1、什么是单例模式
在架构设计时,某些类在整个系统生命周期中最多只能有一个对象存在 ( Single Instance )。如超市收银系统,其外观主要由显示器(1个)、扫描枪(1个)、收款箱(1个)组成,在系统正常运行期间这三部分都是唯一存在的;也就是说,显示器、扫描枪、收款箱这三部分都应该有各自的类,并且每个类只能唯一地实例化一个对象,基于这种模式的程序设计,称为单例模式。
!!!单例模式只能创建一个对象,且该对象的生命周期伴随系统的整个运行期间。
2、怎么实现单例模式
思考:如何定义一个类,使得这个类最多只能创建一个对象?
分析:因为对象是由构造函数创建的,所以我们应该将问题锁定在构造函数上;又因为只能创建一个对象,这就意味着只能调用一次构造函数;显然将构造函数的访问权限设置为 public 不合适,所以,构造函数的访问权限只能是 private。然后,定义一个私有的静态成员 c_instance = NULL 和 公有的静态成员函数,通过 c_instance 来判断是否创建对象。(这个为什么要使用 静态成员呢?因为构造函数是私有的,在类的外部无法创建对象,只能通过类名调用静态成员,而静态成员函数只能调用静态成员变量)
上述分析过程可简化为:
(1)将构造函数的访问属性设置为 private;
(2)定义私有的静态成员属性 instance 并初始化为 NULL;
(3)当需要使用对象时,访问 instance 的值;
1)空值:创建对象,并用 instance 标记;
2)非空值:返回 instance 标记的对象;
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class SObject 7 { 8 static SObject* c_instance; // 定义标识符指针; 9 10 /* 不需用拷贝和赋值,在单例模式中,始终只有一个对象 */ 11 SObject(const SObject&); 12 SObject& operator= (const SObject&); 13 14 SObject() // 私有的构造函数 15 { 16 } 17 public: 18 static SObject* GetInstance(); // 创建对象的入口 19 20 void print() 21 { 22 cout << "this = " << this << endl; 23 } 24 }; 25 26 SObject* SObject::c_instance = NULL; // 静态成员类内声明,类外定义 27 28 SObject* SObject::GetInstance() // 单例模式的关键 29 { 30 if( c_instance == NULL ) 31 { 32 c_instance = new SObject(); 33 } 34 35 return c_instance; 36 } 37 38 int main() 39 { 40 SObject* s = SObject::GetInstance(); 41 SObject* s1 = SObject::GetInstance(); 42 SObject* s2 = SObject::GetInstance(); 43 44 s->print(); // this = 0x940a008 45 s1->print(); // this = 0x940a008 46 s2->print(); // this = 0x940a008 47 48 return 0; 49 } 50 // 注:单例模式中,对象的生命周期存在整个系统运行过程中,所以是绝对不释放的;
· 其实,在上述的单例模式实现案列中,有一部分代码(分析过程中第2、3步)与类本身没有任何关系,既然是这样,我们就把这部分单独提取出来处理。
问题所在:需要使用单例模式时,必须在每个类中定义 静态成员变量 c_instance 和 静态成员函数 GetInstance();当有多个类都需要使用单例模式时,这样的实现方式明显的很冗余,为了能够代码复用,我们可以 将这两部分抽象成一个新类(做成类模板,声明为其它类的友元类,这样与之前的效果一样)。
1 // 对上个单例模式实现代码的改进 2 3 // singleton.hpp 单例模式代码 4 #ifndef SINGLETON_H 5 #define SINGLETON_H 6 7 template 8 < typename T > 9 class Singleton 10 { 11 static T* c_instance; 12 public: 13 static T* GetInstance(); 14 }; 15 16 template 17 < typename T > 18 T* Singleton<T>::c_instance = NULL; 19 20 template 21 < typename T > 22 T* Singleton<T>::GetInstance() 23 { 24 if( c_instance == NULL ) 25 { 26 c_instance = new T(); 27 } 28 29 return c_instance; 30 } 31 32 #endif 33 34 // main.cpp 测试文件 35 #include <iostream> 36 #include <string> 37 #include "singleton.hpp" 38 39 using namespace std; 40 41 class SObject 42 { 43 friend class Singleton<SObject>; // 当前类需要使用单例模式 44 45 SObject(const SObject&); 46 SObject& operator= (const SObject&); 47 48 SObject() 49 { 50 } 51 public: 52 53 void print() 54 { 55 cout << "this = " << this << endl; 56 } 57 }; 58 59 int main() 60 { 61 SObject* s = Singleton<SObject>::GetInstance(); 62 SObject* s1 = Singleton<SObject>::GetInstance(); 63 SObject* s2 = Singleton<SObject>::GetInstance(); 64 65 s->print(); // 0xe63c20 66 s1->print(); // 0xe63c20 67 s2->print(); // 0xe63c20 68 69 return 0; 70 }
在今后工作中,如果一个类(SObject)要使用单例模式(Singleton 单例模式的类模板),只需三步骤:
(1)类(SObject)的构造函数必须私有化;同时,拷贝构造函数、重载=操作符 也私有化;
(2)将单例模式的类模板声明为这个类的友元类; friend class Singleton<SObject>;
(3)通过 单例模式类模板中 SObject* s = Singleton<SObject>::GetInstance(); 创建对象。