摘要:
it人员无论是使用哪种高级语言开发东东,想要更高效有层次的开发程序的话都躲不开三件套:数据结构,算法和设计模式。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案,使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。
设计模式坚持七大原则:开闭原则,单一职责原则,里氏替换原则,依赖倒转原则,接口隔离原则,迪米特原则,合成复用原则,而各项设计模式又区分为三大模式,创建型模式,结构型模式,行为模式。
此系列专注讲解C++开发过程中高需求好用的设计模式类型,能更好的简练项目架构和代码量,通过使用场景以及代码实现来更好的介绍。本文介绍的是单例模式singleton。
(开发环境:VSCode,GCC13.2.0,cmake3.8)
关键词
: C++,设计模式,单例模式,Design pattern,singleton
声明:
本文作者原创,转载请附上文章出处与本文链接。
正文:
介绍
单例模式(Singleton Pattern)是一种常用的软件设计模式,这种类型的设计模式属于创建型模式,其目的确保一个类仅有一个实例,并提供一个访问它的全局访问点。这种模式在需要控制资源访问、实现配置文件的读取或者管理数据库连接等场景下非常有用。
使用场景
正如一个项目一个系统内,只会有一个日志,一个数据中台,一个数据库一个IO一样,把这些模块设计成单例模式可避免对资源的多重占用,减少内存的开销,提高代码可读性和复用性。
在C++中单例或许可以等式于全局变量+命名空间,如果不是为复杂抽象业务,也可以简单用全局变量实现。
单例虽好但现实也有存在很多滥用单例的情况,比如只是以需要一个全局变量为由加了一个单例类,为避免这种情况最好就是特殊模块用单例(做成库),加创建一个命名空间内放置零散的全局变量,函数。
注意事项
- 确保类只有一个实例,并提供一个全局访问点。
- 在多线程环境下,确保单例的唯一性,也即是线程安全。
- 要注意定义与声明分离,不然打包成库引用的话可能会有定义bug。
代码实现
单例模式可以分为懒汉式
和饿汉式
,两者之间的区别在于创建实例的时间不同。
- 懒汉式:延迟加载,即在第一次使用时才创建实例。
- 饿汉式:类加载时就完成实例的初始化,确保线程安全但可能会浪费资源。
比较多的是用lazy_load
懒汉式然后加锁保证线程安全,懒汉式常用的两种方式加锁,一种互斥锁mutex
,另一种使用call_once
。使用互斥锁mutex来给单例加锁的方法是确保同一时刻只能有一个线程取得该锁,其他试图取得该锁的线程阻塞,待持有锁的线程释放独占锁时,才能唤醒取得独占锁后继续运行,而call_once
则是在多线程环境中,确保某个对象只初始化一次,更推荐使用call_once
。
懒汉式(线程安全,使用互斥锁mutex)
#pragma once
#include <mutex>
#include <iostream>
class Singleton
{
public:
// 防止拷贝
Singleton() = default;
Singleton(const Singleton&) = default;
Singleton& operator=(const Singleton&) = default;
static Singleton* GetInstance()
{
// 创建-使用数据库单例,双重锁定
if (singleton == nullptr) {
std::unique_lock<std::mutex> lock(mtx);
if (singleton == nullptr) {
singleton = new Singleton();
singleton->_InitData();
}
}
return singleton;
}
//释放资源
static void Release()
{
if (singleton != NULL) {
delete singleton;
singleton = NULL;
}
}
// 成员函数
// ……
private:
//初始化数据
void _InitData();
static Singleton* singleton;
static std::mutex mtx;
};
Singleton* Singleton::singleton = nullptr;
std::mutex Singleton::mtx;
懒汉式(线程安全,使用call_once)
#pragma once
#include <mutex>
#include <iostream>
class Singleton
{
public:
// 防止拷贝
Singleton() = default;
Singleton(const Singleton&) = default;
Singleton& operator=(const Singleton&) = default;
// 创建-使用数据库单例 lazy_load
static Singleton* GetInstance()
{
static std::once_flag s_flag;
std::call_once(s_flag, [&]()
{
singleton = new Singleton();
singleton->_InitData();
});
return singleton;
}
// 释放资源
static void Release()
{
if (singleton != NULL) {
delete singleton;
singleton = NULL;
}
}
// 成员函数
// ……
private:
//初始化数据
void _InitData();
static Singleton* singleton;
std::unordered_map<std::string, ISSUEDATA> data;
};
Singleton* Singleton::singleton = NULL;
over~
推荐阅读
博客主页:https://blog.csdn.net/weixin_45068267
(客官逛一逛,有许多其它有趣的专栏博文)
C/C++专栏:https://blog.csdn.net/weixin_45068267/category_12268204.html
(内含其它设计模式的介绍和实现)