定义
单例设计模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。这种模式常用于需要控制对某些资源的访问的场景,例如数据库连接、日志记录等。
单例模式涉及以下几个核心元素:
-
私有构造函数 :通过将构造函数设为私有,防止其他类直接创建该类的实例。
-
静态实例 :在类内部创建一个静态变量来保存类的唯一实例。
-
公共静态方法:提供一个公共的静态方法,用于获取该唯一实例。这个方法通常会检查实例是否存在,如果不存在则创建一个新实例。
应用
单例模式适用于以下几种情况:
- 全局访问点
当需要一个全局访问点来访问某个对象时,例如配置管理器、日志记录器或数据库连接池等。
- 资源管理
当一个类负责管理某种资源(如线程池、网络连接、文件句柄等)时,单例模式可以确保该资源的统一管理。
- 状态共享
当多个对象需要共享同一状态时,可以使用单例模式来确保状态的一致性。
- 懒加载
单例模式可以实现懒加载,只有在需要时才初始化实例,从而节省资源。
优缺点
优点
- 控制实例数量:确保系统中只有一个实例。
- 全局访问:通过静态方法提供全局访问点。
- 延迟初始化:可以实现懒加载。
缺点
- 全球状态:单例模式可能导致不可预测的状态,增加了系统的耦合性。
- 线程安全:在多线程环境中,确保单例的线程安全可能会增加复杂性。
- 难以测试:由于全局状态,单例可能会使单元测试变得困难。
总结
单例设计模式在需要确保类只有一个实例并提供全局访问的场景中非常有用。通过谨慎使用,能够有效地管理资源和状态,但也需注意其潜在的缺点。
实例分享
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
/**
* @brief This Singleton class defines the `GetInstance` method that serves as an
* alternative to constructor and lets clients access the same instance of this class
* over and over.
*/
class Singleton {
public:
Singleton(Singleton& other) = delete;
Singleton(Singleton&& other) = delete;
void operator=(const Singleton& other) = delete;
void operator=(const Singleton&& other) = delete;
~Singleton() {}
/**
* @brief This is the static method that controls the access to the singleton instance.
* On the first run, it creates a singleton object and places it into the static filed.
* On the subsequence runs, it returns the clients existing object stored in the static
* field.
* The first time we call GetInstance we will lock the storage location and then we make
* sure again that the variable is null and then we set the value.
*
* @param value
* @return Singleton*
*/
static Singleton* GetInstance(const std::string& value) {
std::lock_guard<std::mutex> lock(mutex_);
if (singleton_ == nullptr) {
singleton_ = new Singleton(value);
}
return singleton_;
}
std::string value() const { return value_; }
private:
/**
* The Singleton's constructor/destructor should always be private to prevent direct
* construction/desctruction calls with the `new`/`delete` operator.
*/
Singleton(const std::string& value) : value_(value) {}
static Singleton* singleton_;
static std::mutex mutex_;
std::string value_;
};
/**
* @brief Static method should be defined outside the class.
*/
Singleton* Singleton::singleton_{nullptr};
std::mutex Singleton::mutex_;
void ThreadFoo(){
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
Singleton* singleton = Singleton::GetInstance("FOO");
std::cout << singleton->value() << "\n";
}
void ThreadBar(){
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
Singleton* singleton = Singleton::GetInstance("BAR");
std::cout << singleton->value() << "\n";
}
int main() {
std::cout <<"If you see the same value, then singleton was reused!\n" <<
"If you see different values, then 2 singletons were created!\n\n" <<
"RESULT:\n";
std::thread t1(ThreadFoo);
std::thread t2(ThreadBar);
t1.join();
t2.join();
return 0;
}