设计模式 - 单例模式
设计模式 - 单列模式
单例模式(Singleton Pattern)
定义: 单例模式(Singleton Pattern)是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。该模式通过控制实例的创建过程来避免多次创建同一个对象。
单例模式的关键点:
- 只有一个实例:确保某个类在整个系统中只有一个实例。
- 全局访问点:提供一个静态方法来访问该实例,确保全局可以访问到这个唯一实例。
单例模式的结构:
- 静态实例:类内部有一个静态的实例,只有该类能够访问它。
- 私有构造函数:构造函数被声明为私有,避免外部通过构造函数来创建新的实例。
- 静态方法:提供一个公共的静态方法(通常称为
getInstance()
)来获取该实例。
实现方式
1. 懒汉式(Lazy Initialization)
懒汉式单例是在第一次使用时才创建实例,因此延迟了实例的创建,适合实例化过程较为复杂的对象。
#include <iostream>
class Singleton {
public:
// 获取唯一实例
// 静态成员函数可以在没有实例化对象的时候用类名去调用
static Singleton* getInstance() {
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
// 示例方法
void showMessage() {
std::cout << "Hello, Singleton!" << std::endl;
}
private:
// 私有构造函数,外部无法直接创建实例
Singleton() {
std::cout << "Singleton Instance Created!" << std::endl;
}
// 禁止拷贝构造和赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* instance; // 静态实例
};
// 静态成员初始化
Singleton* Singleton::instance = nullptr;
int main() {
Singleton* singleton1 = Singleton::getInstance();
singleton1->showMessage(); // 输出: Hello, Singleton!
Singleton* singleton2 = Singleton::getInstance();
singleton2->showMessage(); // 输出: Hello, Singleton!
return 0;
}
说明:
instance
是一个静态指针,指向类的唯一实例。- 通过
getInstance()
方法来获取实例,在首次访问时创建该实例。 - 线程不安全:这种方式在多线程环境下可能会导致多个实例的创建。
2. 线程安全的懒汉式(Lazy Initialization, Thread-Safe)
为了避免多线程环境中出现多个实例,通常可以通过加锁来确保线程安全。
#include <iostream>
#include <mutex>
class Singleton {
public:
static Singleton* getInstance() {
std::lock_guard<std::mutex> lock(mutex); // 加锁确保线程安全
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
void showMessage() {
std::cout << "Hello, Singleton!" << std::endl;
}
private:
Singleton() {
std::cout << "Singleton Instance Created!" << std::endl;
}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* instance;
static std::mutex mutex; // 用于同步访问
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;
int main() {
Singleton* singleton1 = Singleton::getInstance();
singleton1->showMessage(); // 输出: Hello, Singleton!
Singleton* singleton2 = Singleton::getInstance();
singleton2->showMessage(); // 输出: Hello, Singleton!
return 0;
}
说明:
- 在多线程环境下,
std::mutex
用来确保同一时刻只有一个线程可以创建Singleton
实例。 - 通过
std::lock_guard<std::mutex>
来管理锁的生命周期。
3. 饿汉式(Eager Initialization)
饿汉式单例模式在类加载时就创建实例,避免了多线程环境中的同步问题。它适用于实例的创建过程简单且不依赖其他资源的场景。
#include <iostream>
class Singleton {
public:
// 获取唯一实例
static Singleton* getInstance() {
return &instance; // 返回静态实例
}
void showMessage() {
std::cout << "Hello, Singleton!" << std::endl;
}
private:
// 静态实例,类加载时即创建
static Singleton instance;
// 私有构造函数,外部无法直接创建实例
Singleton() {
std::cout << "Singleton Instance Created!" << std::endl;
}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
// 静态实例初始化(全局对象)
Singleton Singleton::instance;
int main() {
Singleton* singleton1 = Singleton::getInstance();
singleton1->showMessage(); // 输出: Hello, Singleton!
Singleton* singleton2 = Singleton::getInstance();
singleton2->showMessage(); // 输出: Hello, Singleton!
return 0;
}
说明:
- 静态成员 instance 在类加载时就会创建实例,因此无需加锁。
- 利用静态全局变量,在进入main前就创建示例化
- 没有延迟加载,适用于那些实例创建过程简单且不依赖其他资源的情况。
4. 懒汉式 + 双重锁机制(Double-Checked Locking)
双重锁机制是一种优化方案,结合了懒汉式和线程安全的特点,只有在首次实例化时加锁,后续访问时无需加锁。
#include <iostream>
#include <mutex>
class Singleton {
public:
static Singleton* getInstance() {
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mutex); // 加锁
if (instance == nullptr) { // 再次检查实例是否为空
instance = new Singleton();
}
}
return instance;
}
void showMessage() {
std::cout << "Hello, Singleton!" << std::endl;
}
private:
Singleton() {
std::cout << "Singleton Instance Created!" << std::endl;
}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* instance;
static std::mutex mutex;
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;
int main() {
Singleton* singleton1 = Singleton::getInstance();
singleton1->showMessage(); // 输出: Hello, Singleton!
Singleton* singleton2 = Singleton::getInstance();
singleton2->showMessage(); // 输出: Hello, Singleton!
return 0;
}
说明:
- 只有在示例对象指针为空的时候才去获取锁,并且再次判断,这样再已经实例化后就不用再去互斥,这样在后续减少开销了。
- 双重锁机制减少了在后续获取实例时的加锁开销,仅在实例为空时才加锁。
- 在多线程环境下,它确保了只有第一个线程会执行实例的创建。
总结:
- 单例模式确保类只有一个实例,并提供全局访问点。
- 懒汉式:延迟实例化,适合实例化过程复杂的情况,但多线程环境下需要注意线程安全。
- 饿汉式:在类加载时即创建实例,简单而线程安全,但不适合资源消耗较大的实例。
- 双重锁机制:一种线程安全的懒汉式实现,减少了锁的开销。