创建型模式-单例模式

365beat怎么下载苹果 📅 2026-01-08 03:48:01 ✍️ admin 👁️ 7266 ❤️ 523
创建型模式-单例模式

创建型模式-单例模式

目录创建型模式-单例模式1. 意图2. 动机3. 解决方法4. 单例模式结构5. 实现5.1 懒汉式-单线程-手动释放版5.2 懒汉式-单线程-自动释放版5.3 懒汉式-多线程版5.4 懒汉式-Meyer's Singleton(推荐)5.5 饿汉式5.6 宏实现版本5.7 模板版本5.8 宏+模板(推荐)6. 使用场景和优缺点7. 参考

1. 意图

意图是模式的简短、精炼的一句话总结,回答“这个模式是什么”的问题。

单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。

2. 动机

动机是解释为什么需要这个模式,描述模式要解决的具体问题和场景。

对于一些类中,只有一个实例是很重要的。例如一个系统中,只应该有一个文件系统和窗口管理器,

3. 解决方法

所有单例的实现都包含以下两个相同的步骤:

将默认构造函数设为私有或者保护, 防止其他对象使用单例类的 new运算符。

新建一个静态构建方法作为构造函数。 该函数会 “偷偷” 调用私有构造函数来创建对象, 并将其保存在一个静态成员变量中。 此后所有对于该函数的调用都将返回这一缓存对象。

如果你的代码能够访问单例类, 那它就能调用单例类的静态方法。 无论何时调用该方法, 它总是会返回相同的对象。

4. 单例模式结构

5. 实现

5.1 懒汉式-单线程-手动释放版

"懒"的体现:“节能体现”,只在第一次调用 getInstance() 时才创建实例,不到万不得已(真正需要)绝不创建对象。

class USingleton

{

public:

// 全局访问点

static USingleton* getInstance()

{

if (instance == nullptr)

{

instance = new USingleton();

}

return instance;

}

void doSomething()

{

std::cout << "Doing something..." << std::endl;

}

// 清理资源(可选)

static void destroy()

{

delete instance;

instance = nullptr;

}

private:

static USingleton* instance;

// 私有构造函数

USingleton() = default;

// 私有拷贝构造函数和赋值运算符

USingleton(const USingleton&) = delete;

USingleton& operator=(const USingleton&) = delete;

};

/// xxx.cpp

// 静态成员初始化

USingleton* USingleton::instance = nullptr;

特性

懒加载:首次调用getInstance()时才创建实例

简单直观:最基础的单例实现

内存泄漏风险:需要手动调用destroy()清理

优点

缺点

✅ 实现简单:代码简洁,易于理解

❌ 非线程安全:多线程下可能创建多个实例

✅ 延迟初始化:节省启动时资源占用

❌ 内存泄漏风险:C++中需手动管理内存

✅ 代码直观:适合教学单例模式原理

❌ 违反RAII:不符合C++资源管理最佳实践

✅ 灵活控制:可控制初始化时机

❌ 异常不安全:构造函数异常可能导致状态不一致

❌ 效率问题:线程安全版本需加锁影响性能

5.2 懒汉式-单线程-自动释放版

借助类成员变量(内部类,完成内部类自动析构调用)。

class USingleton

{

public:

// 全局访问点

static USingleton* getInstance()

{

if (instance == nullptr)

{

instance = new USingleton();

std::cout << "construct ..." << std::endl;

}

return instance;

}

void doSomething()

{

std::cout << "Doing something..." << std::endl;

}

private:

// 内部类,用于垃圾回收

class GC

{

public:

~GC()

{

if (instance != NULL)

{

delete instance;

instance = nullptr;

std::cout << "destroy ..." << std::endl;

}

}

};

static GC gc;

private:

static USingleton* instance;

// 私有构造函数

USingleton() = default;

// 私有拷贝构造函数和赋值运算符

USingleton(const USingleton&) = delete;

USingleton& operator=(const USingleton&) = delete;

};

/// xxx.cpp

// 在程序启动前就创建实例

USingleton* USingleton::instance = nullptr;

//全局静态变量,会被自动销毁,从而实现对单例的垃圾回收

USingleton::GC USingleton::gc;

5.3 懒汉式-多线程版

双重检查锁定版本-关键实现代码:

class USingleton

{

public:

// 全局访问点

static USingleton* getInstance()

{

// 第一次检查(无锁)

if (instance == nullptr) {

// 获取锁

std::lock_guard lock(mutex);

// 第二次检查(持有锁)

if (instance == nullptr)

{

instance = new USingleton();

std::cout << "construct ..." << std::endl;

}

}

return instance;

}

void doSomething()

{

std::cout << "Doing something..." << std::endl;

}

// 清理资源(可选)

static void destroy()

{

std::lock_guard lock(mutex);

if (instance != nullptr)

{

delete instance;

instance = nullptr;

std::cout << "~destory ..." << std::endl;

}

}

private:

static USingleton* instance;

static std::mutex mutex;

// 私有构造函数

USingleton() = default;

// 私有拷贝构造函数和赋值运算符

USingleton(const USingleton&) = delete;

USingleton& operator=(const USingleton&) = delete;

};

/// xxx.cpp

// 静态成员初始化

USingleton* USingleton::instance = nullptr;

std::mutex USingleton::mutex;

5.4 懒汉式-Meyer's Singleton(推荐)

这是一种基于局部静态变量的懒汉式单例实现,由C++专家Scott Meyers在《Effective C++》中提出,被认为是现代C++中最优雅的单例实现。

在单例模式中,坚持使用返回引用(Meyer's方式),除非有特殊需求(如需要兼容C接口)。不要因为"可以转换"就随意混用(返回指针形式),保持代码的清晰性和一致性更重要。

class USingleton

{

public:

// 全局访问点

static USingleton& getInstance()

{

static USingleton s_us_inst;

return s_us_inst;

}

void doSomething()

{

std::cout << "Doing something..." << std::endl;

}

private:

// 私有构造函数

USingleton() = default;

// 私有拷贝构造函数和赋值运算符

USingleton(const USingleton&) = delete;

USingleton& operator=(const USingleton&) = delete;

};

5.5 饿汉式

饿汉式最核心的体现就是 "时间确定性"。它在程序生命周期的最早期(main函数执行之前)就完成初始化,这种设计哲学认为:

"已知的坏消息优于未知的惊喜":宁愿在启动时就知道失败,也不要在业务高峰时突然崩溃

"确定的延迟优于不确定的等待":把初始化延迟明确放在启动阶段,而不是隐藏在业务调用中

"可控的启动过程优于随机的运行时行为":系统管理员可以明确知道"程序要么完全启动成功,要么完全失败"

class USingleton

{

public:

// 全局访问点

static USingleton& getInstance()

{

return s_us_inst;

}

void doSomething()

{

std::cout << "Doing something..." << std::endl;

}

private:

// 私有构造函数

USingleton() = default;

static USingleton s_us_inst;

// 私有拷贝构造函数和赋值运算符

USingleton(const USingleton&) = delete;

USingleton& operator=(const USingleton&) = delete;

};

/// xxx.cpp 在程序启动前就创建实例

USingleton USingleton::s_us_inst;

5.6 宏实现版本

针对单例的实现,如果程序中存在多个,那么其实现大致相同,导致重复代码的出现。可以使用模板或者宏的方式来解决重复度。

// singleton_macro_simple.h

#ifndef SINGLETON_MACRO_SIMPLE_H

#define SINGLETON_MACRO_SIMPLE_H

#include

// 声明和实现在一起(适合头文件只有的情况)

#define SINGLETON(classname) \

private: \

static classname* instance; \

static std::mutex mtx; \

classname() {} \

classname(const classname&) = delete; \

classname& operator=(const classname&) = delete; \

public: \

static classname* getInstance() { \

if (instance == nullptr) { \

std::lock_guard lock(mtx); \

if (instance == nullptr) { \

instance = new classname(); \

} \

} \

return instance; \

} \

static void destroy() { \

std::lock_guard lock(mtx); \

if (instance != nullptr) { \

delete instance; \

instance = nullptr; \

} \

}

// 在cpp文件中定义静态成员

#define SINGLETON_INSTANCE(classname) \

classname* classname::instance = nullptr; \

std::mutex classname::mtx;

#endif

/// 测试类

class USingleton

{

SINGLETON(USingleton)

public:

void doSomething()

{

std::cout << "Doing something..." << std::endl;

}

};

/// xxx.cpp

#include "TestSingleton.h"

SINGLETON_INSTANCE(USingleton)

5.7 模板版本

// 更好的方案:使用模板而不是宏

template

class Singleton {

protected:

Singleton() = default;

public:

Singleton(const Singleton&) = delete;

Singleton& operator=(const Singleton&) = delete;

static T& getInstance() {

static std::once_flag initFlag;

static T* instance = nullptr;

std::call_once(initFlag, []() {

instance = new T();

});

return *instance;

}

};

/// 测试类

class USingleton : public Singleton

{

public:

void doSomething()

{

std::cout << "Doing something..." << std::endl;

}

};

5.8 宏+模板(推荐)

// 首先需要定义Singleton模板类

template

class Singleton {

public:

static T& getInstance()

{

static T s_instance;

return s_instance;

}

protected:

Singleton() = default;

virtual ~Singleton() = default;

// 禁止拷贝和赋值

Singleton(const Singleton&) = delete;

Singleton& operator=(const Singleton&) = delete;

};

// 宏定义

#define SINGLETON_DECLARE(ClassName) \

private: \

ClassName(); \

ClassName(const ClassName&) = delete; \

ClassName& operator=(const ClassName&) = delete; \

friend class Singleton; \

public: \

static ClassName& getInstance() { \

return Singleton::getInstance(); \

} \

static ClassName* pointer() { \

return &getInstance(); \

}

/// 测试类

class USingleton

{

SINGLETON_DECLARE(USingleton)

public:

void doSomething()

{

std::cout << "Doing something..." << std::endl;

}

};

/// xxx.cpp

#include "TestSingleton.h"

USingleton::USingleton()

{

std::cout << "Hello, World" << std::endl;

}

注意,如果在宏定义中, ClassName()声明了没有实现,则需要在对应的cpp中实现构造函数。

6. 使用场景和优缺点

如果程序中的某个类对于所有客户端只有一个可用的实例, 可以使用单例模式。

如果你需要更加严格地控制全局变量, 可以使用单例模式。

优缺点对比总结

方面

优势

劣势

实例控制

✅ 严格保证唯一性

❌ 灵活性受限

访问便利性

✅ 全局直接访问

❌ 可能造成过度使用

资源管理

✅ 延迟初始化节省资源

❌ 多线程下资源竞争

设计原则

-

❌ 违反单一职责原则

代码质量

-

❌ 可能掩盖设计缺陷

可测试性

-

❌ 单元测试困难

7. 参考

书籍:《设计模式:可复用面向对象软件的基础》;

单例的模版+宏的实现 | 公孙二狗

AI: DeepSeek

相关推荐

(系列共7款)全称:三星 I9308(GALAXY S3)
365beat怎么下载苹果

(系列共7款)全称:三星 I9308(GALAXY S3)

📅 11-03 👁️ 3306
普联TPLink路由器初始密码
体育365投注官网

普联TPLink路由器初始密码

📅 10-18 👁️ 2184
小米15Pro寿命一般几年
Microsoft 365安卓

小米15Pro寿命一般几年

📅 08-12 👁️ 8603