软件设计模式之单例模式
文章目录
- 软件设计模式之单例模式
- 什么是单例模式
- 实现方式
- 饿汉式
- 懒汉式
- 双重检查锁
- 静态内部类
- 枚举
- 优缺点
- 优点
- 缺点
- 使用场景
软件设计模式之单例模式
什么是单例模式
单例设计模式(Singleton Pattern)是一种创建型设计模式,旨在确保一个类只有一个实例,并提供一个全局访问点来访问该实例。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。
简而言之,就是全局只有一个对象实例
实现方式
单例模式的实现方式有多种,以下是几种常见的实现方式:
饿汉式
饿汉式在类加载时就创建实例,因此线程安全,但可能会浪费内存。
//饿汉模式
//核心思想:在类加载时立即初始化单例对象
class SingLeton
{public:static SingLeton& getInstance(){return _eton;}int getData(){return _data;}protected:private:int _data;private:static SingLeton _eton;SingLeton():_data(666) {std::cout << "单例对象构造" << std::endl;};~SingLeton() {};SingLeton(const SingLeton& eton) = delete;
};SingLeton SingLeton::_eton;
懒汉式
懒汉式在第一次使用时才创建实例,节省资源,但需要加锁以确保线程安全。
//懒汉模式
//核心思想:延迟初始化,仅在首次请求时创建实例
class SingLeton
{public:static SingLeton& getInstance(){static SingLeton _eton;return _eton;}int getData(){return _data;}protected:private:int _data;private:SingLeton():_data(666) {std::cout << "单例对象构造" << std::endl;};~SingLeton() {};SingLeton(const SingLeton& eton) = delete;
};
双重检查锁
双重检查锁在多线程环境下性能较好,但实现较复杂。
#include <mutex>
#include <atomic>class Singleton {
private:static std::atomic<Singleton*> instance;static std::mutex mtx;Singleton() = default;~Singleton() = default;Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;public:static Singleton* getInstance() {Singleton* tmp = instance.load(std::memory_order_acquire);if (tmp == nullptr) {std::lock_guard<std::mutex> lock(mtx);tmp = instance.load(std::memory_order_relaxed);if (tmp == nullptr) {tmp = new Singleton();instance.store(tmp, std::memory_order_release);}}return tmp;}
};// 静态成员初始化
std::atomic<Singleton*> Singleton::instance{nullptr};
std::mutex Singleton::mtx;
静态内部类
静态内部类方式既能确保线程安全,又能实现延迟加载。
// Meyer's Singleton (C++11起线程安全)
class Singleton {
public:static Singleton& getInstance() {static Singleton instance;return instance;}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;
private:Singleton() = default;~Singleton() = default;
};
枚举
class Singleton {
public:enum { INSTANCE };static Singleton& getInstance() {static Singleton instance;return instance;}void showMessage() {std::cout << "Singleton instance created" << std::endl;}private:Singleton() {}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;
};int main() {Singleton::getInstance().showMessage();return 0;
}
优缺点
优点
-
资源管理:单例模式能高效管理共享资源,确保程序内仅存在单一对象实例,从而降低资源消耗和内存占用。
-
全局访问:该模式提供了全局访问唯一对象的便捷途径,使得程序各模块都能轻松获取和使用该实例。
-
线程安全:在多线程环境中,单例模式确保仅有一个线程能创建实例,有效防止竞态条件和数据不一致问题。
-
创建控制:通过集中管理对象创建过程,单例模式避免了程序多处随意实例化对象的情况,提升了代码的可维护性和控制性。
缺点
-
灵活性不足:单例模式严格限制对象实例化,在特定场景下会降低系统灵活性。若后续开发需要支持多实例,往往需要进行较大规模的代码调整。
-
高耦合问题:该模式将对象创建与使用紧密绑定,容易导致其他模块过度依赖单例对象,从而影响系统的可维护性和扩展性。
-
测试复杂度高:单元测试时,单例对象需要特殊的环境模拟,这种额外的测试准备增加了测试工作的难度。
-
全局状态风险:作为全局访问点,单例对象在多线程或分布式环境中可能引发并发问题,必须谨慎处理线程安全和锁机制。
-
扩展性受限:当需要增强或修改单例功能时,往往涉及模式重构,这不仅提高了系统复杂度,也增加了维护难度。
使用场景
单例模式适用于以下场景:
- 唯一序列号生成需求
- Web 应用计数器实现
- 数据库连接管理:采用单例模式实现数据库连接管理器,确保应用全局共享单一连接实例,有效减少连接创建和释放的资源消耗
- 配置统一管理:通过单例对象封装应用配置信息,保证系统配置一致性,消除配置冲突风险
- 稀缺资源管控:对文件句柄、网络连接等有限资源,运用单例模式实现统一调度与分配
- 集中日志管理:基于单例模式构建全局日志记录器,为系统各模块提供统一日志接口,便于日志的集中维护
- 应用主控入口:采用单例模式实现应用主入口,确保启动和初始化流程仅执行一次,提供标准化的程序入口