单例模式(Singleton Pattern)是最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意

  1. 单例类只能有一个实例
  2. 单例类必须自己创建自己的唯一实例
  3. 单例类必须给所有其他对象提供这一实例
  4. 构造函数私有防止被其他类创建

优点

  1. 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
  2. 避免对资源的多重占用(比如写文件操作)。

缺点

没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化

使用场景

  1. 要求生产唯一序列号
  2. WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来
  3. 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等

分类

  • 懒汉式:类初始化延迟到第一次获取实例,延迟加载,减少可能不需要的资源消耗
  • 饿汉式:程序初始化即初始化好实例,获取实例加快,占用固定资源

示例

  1. #include "pch.h"
  2. #include <iostream>
  3. #include <mutex>
  4. // 懒汉式(线程安全)
  5. class LazyManager
  6. {
  7. public:
  8. static LazyManager* getInstance()
  9. {
  10. if (nullptr == _pDisplayManager)
  11. {
  12. _initLock.lock();
  13. {
  14. if (nullptr == _pDisplayManager)
  15. {
  16. _pDisplayManager = new LazyManager();
  17. }
  18. }
  19. _initLock.unlock();
  20. }
  21. return _pDisplayManager;
  22. }
  23. void SayHi()
  24. {
  25. std::cout << "I am lazy" << std::endl;
  26. }
  27. private:
  28. // 构造函数私有
  29. LazyManager()
  30. {
  31. std::cout << "Lazy Manager Construct" << std::endl;
  32. };
  33. static bool _hasInited;
  34. static std::mutex _initLock;
  35. static LazyManager* _pDisplayManager;
  36. };
  37. LazyManager* LazyManager::_pDisplayManager = nullptr;
  38. std::mutex LazyManager::_initLock;
  39. bool LazyManager::_hasInited = false;
  40. // 饿汉式(线程安全)
  41. class HungryManager
  42. {
  43. public:
  44. static HungryManager* getInstance()
  45. {
  46. return _hungryManager;
  47. }
  48. void SayHi()
  49. {
  50. std::cout << "I am hungry" << std::endl;
  51. }
  52. private:
  53. // 构造函数私有
  54. HungryManager()
  55. {
  56. std::cout << "Lazy Manager Construct" << std::endl;
  57. }
  58. static HungryManager* _hungryManager;
  59. };
  60. HungryManager* HungryManager::_hungryManager = new HungryManager();
  61. // 调用示例
  62. int main()
  63. {
  64. LazyManager* lazyManager = LazyManager::getInstance();
  65. LazyManager* lazyManager2 = LazyManager::getInstance();
  66. lazyManager->SayHi();
  67. lazyManager2->SayHi();
  68. HungryManager* hungryManager = HungryManager::getInstance();
  69. HungryManager* hungryManager2 = HungryManager::getInstance();
  70. hungryManager->SayHi();
  71. hungryManager2->SayHi();
  72. }
>>>
Lazy Manager Construct
Lazy Manager Construct
I am lazy
I am lazy
I am hungry
I am hungry