C++设计模式——Singleton单例模式

打印 上一主题 下一主题

主题 776|帖子 776|积分 2328

一、单例模式的界说  

单例模式,英文全称Singleton Pattern,是一种创建型设计模式,它包管一个类在程序中仅有一个实例,并对外提供一个访问的该类实例的全局接口。
单例模式通常用于需要控制对象资源的开发场景,一个类只创建一个对象的设计,既可以避免创建过多副本所造成的资源浪费现象,又可以避免引发数据一致性等问题。
在数据库连接、线程池设计、日记系统设计等开发场景,常常利用单例模式来创建对象,可以有用地低落对内存资源的占用。
在编码时,为了防止外部直接通过new关键字创建对象实例,Singleton类的构造函数必须是私有的。
在多线程开发场景,单例模式可以避免多个线程同时访问同一个资源,从而避免资源竞争的问题,如果还需要进一步包管线程安全性,可以在创建实例时添加同步锁。


单例模式在现实生活中的抽象实例:
电力公司:在一个城市或地区,通常只有一个电力公司负责供电,我们可以通过该公司来获取电力服务。
总统办公室:在一个国家,通常只有一个总统办公室负责国家变乱处置惩罚,办公室负责确保国家变乱的一致性和高效运作。
登录系统:用户只需要登录一次就可以打开多个应用程序的界面。

二、单例模式的结构

单例模式重要包含以下组件:
1.Singleton类:这是一个单例类,它在整个系统中只有一个实例。通常利用私有构造函数来创建、利用公共静态成员方法来访问。
2.私有构造函数:为了避免被外部实例化,Singleton类通常会界说一个私有构造函数,使得其他类无法通过调用构造函数创建Singleton的实例对象。
3.私有静态成员变量:Singleton类通常会声明一个私有静态成员变量,用来生存Singleton的唯一实例,且这个静态变量只能在Singleton类内部访问。
4.公共的对外接口:它通常被命名为getInstance(),通过该接口可以获取Singleton的唯一实例对象。该接口利用懒汉/饿汉的方式来实现,在接口内部会先判断实例是否已经存在,如果存在则直接返回,否则创建一个新的实例并返回。

组件之间的工作步调如下:
1.饿汉模式的程序启动:在程序启动的同时就创建好Singleton实例,并提供全局唯一的外部访问接口,外部程序可以直接调用该接口来获取Singleton实例。
2.懒汉模式的程序启动:程序启动时并不会创建Singleton实例,程序在等到单例对象被第一次利用时才创建Singleton实例。
3.接纳私有的静态变量存储已经创建好的Singleton实例。
4.外部客户端通过唯一的外部访问接口来访问并利用Singleton实例。

饿汉模式单例 & 懒汉模式单例:
饿汉模式(Singleton with Instantiation):
是一种线程安全的实现方法,在类初始化时就完成了单例实例的创建。

懒汉模式(Singleton with Lazy Initialization):
也被称为"双检锁"模式,只有当第一次真正需要获取单例实例时才举行单例实例的创建。

饿汉模式和懒汉模式都实现了单例,即包管在整个应用程序的生命周期中只有一个Singleton类实例。
饿汉模式的优点是线程安全,但缺点是如果该实例很复杂会增长初始化的耗时,从而导致程序的启动时间被延长。
懒汉模式的优点是耽误加载,可以节约资源和减少程序的启动耗时,缺点是需要考虑多线程情况下创建对象导致的线程安全问题,它通常在外部访问接口中利用双重查抄锁定(Double-checked locking)来包管线程安全。

对应UML类图:

三、单例模式代码样例

1.单例模式的伪代码:
  1. #include <iostream>
  2. class Singleton {
  3. private:
  4.     static Singleton* instance;
  5.    
  6.     //私有构造函数,确保不能从外部实例化对象
  7.     Singleton() {}
  8.    
  9. public:
  10.     //获取单例实例的静态方法
  11.     static Singleton* getInstance() {
  12.         if (instance == nullptr) {
  13.             instance = new Singleton();
  14.         }
  15.         return instance;
  16.     }
  17. };
  18. Singleton* Singleton::instance = nullptr;
  19. int main() {
  20.     Singleton* singleton = Singleton::getInstance();
  21.     return 0;
  22. }
复制代码
2.单例模式的加锁版伪代码:
  1. class Singleton {
  2. private:
  3.     static Singleton* instance;
  4.     Singleton() {} //私有化构造函数,防止外部创建实例
  5. public:
  6.     static Singleton* getInstance() {
  7.         if (instance == nullptr) {
  8.             //在多线程环境下需要加锁保证只创建一个实例
  9.             // std::lock_guard<std::mutex> lock(mutex);
  10.             instance = new Singleton();
  11.         }
  12.         return instance;
  13.     }
  14.     //单例类的其他成员函数
  15.     void doSomething() {
  16.         // ...
  17.     }
  18. };
  19. Singleton* Singleton::instance = nullptr;
  20. int main() {
  21.     Singleton* obj1 = Singleton::getInstance();
  22.     obj1->doSomething();
  23.     Singleton* obj2 = Singleton::getInstance();
  24.     obj2->doSomething();
  25.     delete obj1; //释放资源
  26.     return 0;
  27. }
复制代码
3.饿汉模式的伪代码:
  1. class Singleton {
  2. private:
  3.     static Singleton* instance;
  4.     //私有构造函数,防止外部直接创建对象
  5.     Singleton() {}
  6. public:
  7.     //静态成员函数,用于获取单例对象
  8.     static Singleton* getInstance() {
  9.         return instance;
  10.     }
  11. };
  12. //提前创建好单例对象
  13. Singleton* Singleton::instance = new Singleton();
复制代码
4.懒汉模式的伪代码:
  1. class Singleton {
  2. private:
  3.     static Singleton* instance;
  4.     Singleton() {}
  5. public:
  6.     //使用时才创建单例对象
  7.     static Singleton* getInstance() {
  8.         if (instance == nullptr) {
  9.             instance = new Singleton();
  10.         }
  11.         return instance;
  12.     }
  13. };
复制代码
Demo1:完整代码实现
  1. #include <iostream>
  2. class Singleton {
  3. private:
  4.     static Singleton* instance;
  5.     Singleton() {}
  6. public:
  7.     static Singleton* getInstance() {
  8.         if (instance == nullptr) {
  9.             instance = new Singleton();
  10.         }
  11.         return instance;
  12.     }
  13.     void showMessage() {
  14.         std::cout << "Hello, World!" << std::endl;
  15.     }
  16. };
  17. Singleton* Singleton::instance = nullptr;
  18. int main() {
  19.     // 获取Singleton对象实例
  20.     Singleton* singleton = Singleton::getInstance();
  21.    
  22.     // 调用对象的方法
  23.     singleton->showMessage();
  24.    
  25.     return 0;
  26. }
复制代码
运行结果:
  1. Hello, World!
复制代码
Demo2:增长析构函数
  1. #include <iostream>
  2. class Singleton {
  3.     public:
  4.     static Singleton& getInstance()
  5.     {
  6.         //如果对象实例不存在就创建一个
  7.         if (!instance) {
  8.             instance = new Singleton();
  9.         }
  10.         return *instance;
  11.     }
  12.     //给外部调用的接口
  13.     void Operation()
  14.     {
  15.         std::cout
  16.             << "Singleton is performing some operation."
  17.             << std::endl;
  18.     }
  19.     Singleton(const Singleton&) = delete;
  20.     Singleton& operator=(const Singleton&) = delete;
  21.     private:
  22.     //私有化的构造函数
  23.     Singleton()
  24.     {
  25.         std::cout << "Singleton instance created."
  26.             << std::endl;
  27.     }
  28.     //私有化的析构函数
  29.     ~Singleton()
  30.     {
  31.         std::cout << "Singleton instance destroyed."
  32.             << std::endl;
  33.     }
  34.     static Singleton* instance;
  35. };
  36. Singleton* Singleton::instance = nullptr;
  37. int main()
  38. {
  39.     Singleton& singleton = Singleton::getInstance();
  40.     singleton.Operation();
  41.     return 0;
  42. }
复制代码
运行结果:
  1. Singleton instance created.
  2. Singleton is performing some operation.
复制代码
四、单例模式的优缺点

单例模式的优点:
可以有用限制资源的数量,对于那些需要全局访问的资源,单例模式可以包管该资源只有一个实例。
对象的创建/烧毁过程最多只有一次,可以节省系统开销。
可以统一管理全局配置,如果单例模式的对象用来存储一些配置信息,可以实现对全局配置的管理。
简化了访问资源的入口,由于全局只有一个实例,使得客户端只需要关注一个访问入口即可。
 
单例模式的缺点:
缺乏机动性,一旦创建了单例对象,就不能更改实在例化过程。
限制了一个类只能有一个实例,难以扩展该类的功能。
由于单例对象是全局可访问的,大概引发全局变量的滥用。
存在线程安全隐患,如果不增长一些锁机制,在多线程情况下大概会创建多个实例,影响单例的特性。

五、代码实战

  1. #include <iostream>
  2. using namespace std;
  3. class Singleton
  4. {
  5.     private:
  6.     static bool instanceFlag;
  7.     static Singleton* single;
  8.     Singleton()
  9.     {
  10.         printf("Private constructor finished.\n");
  11.     }
  12.     public:
  13.     static Singleton* getInstance();
  14.     void method();
  15.     ~Singleton()
  16.     {   
  17.         printf("Public de-constructor finished.\n");
  18.         instanceFlag = false;
  19.     }
  20. };
  21. bool Singleton::instanceFlag = false;
  22. Singleton* Singleton::single = NULL;
  23. Singleton* Singleton::getInstance()
  24. {
  25.     if (!instanceFlag)
  26.     {
  27.         single = new Singleton();
  28.         instanceFlag = true;
  29.         return single;
  30.     }
  31.     else
  32.     {
  33.         return single;
  34.     }
  35. }
  36. void Singleton::method()
  37. {
  38.     cout << "Method of the singleton class" << endl;
  39. }
  40. int main()
  41. {
  42.     Singleton* sc1, * sc2;
  43.     sc1 = Singleton::getInstance();
  44.     sc1->method();
  45.     sc2 = Singleton::getInstance();
  46.     sc2->method();
  47.     delete sc1, sc2;
  48.     return 0;
  49. }
复制代码
运行结果:
  1. Private constructor finished.
  2. Method of the singleton class
  3. Method of the singleton class
  4. Public de-constructor finished.
复制代码
六、参考阅读

https://www.geeksforgeeks.org/singleton-pattern-c-design-patterns/
https://scottlilly.com/c-design-patterns-the-singleton-pattern/
https://www.tutorialspoint.com/explain-cplusplus-singleton-design-pattern
https://www.codeproject.com/Articles/1921/Singleton-Pattern-its-implementation-with-Cplusplu

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

魏晓东

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表