意图
单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。
问题
单例模式解决了两个问题
- 保证一个类只有一个实例。每次调用普通构造函数都会返回一个新对象。而采用单例模式可以保证每次创建新对象时,会返回一个已创建的对象。
- 为该实例提供一个全局访问节点。和全局变量一样, 单例模式也允许在程序的任何地方访问特定对象。 但是它可以保护该实例不被其他代码改写。
解决方案
单例模式的实现包含以下两个步骤:
- 将默认构造函数设为私有, 防止其他对象使用单例类的
new运算符。 - 新建一个静态构建方法作为构造函数。 该函数会 “偷偷” 调用私有构造函数来创建对象, 并将其保存在一个静态成员变量中。 此后所有对于该函数的调用都将返回这一缓存对象。
单例模式结构
- 单例 (Singleton) 类声明了一个名为
getInstance获取实例的静态方法来返回其所属类的一个相同实例。该方法是获取单例对象的唯一方式。
代码实现
#include<iostream>
#include<string>
using namespace std;
class Singleton {
private:
// 保存单例实例的成员变量必须被声明为静态类型。
static Singleton* singleton_;
// 单例的构造函数必须永远是私有类型,以防止使用`new`运算符直接调用构
// 造方法。
Singleton(const std::string value) : value_(value)
{
}
string value_;
public:
Singleton(Singleton& other) = delete;
void operator=(const Singleton&) = delete;
// 用于控制对单例实例的访问权限的静态方法。
static Singleton* get_instance(const string& value);
//任何单例都必须定义一些可在其实例上执行的业务逻辑。
void SomeBusinessLogic()
{
cout << "value/2:" << singleton_->value_/2 << endl;
}
std::string value() const {
return value_;
}
};
Singleton* Singleton::singleton_ = nullptr;
Singleton *Singleton::get_instance(const std::string& value)
{
if (singleton_ == nullptr) {
singleton_ = new Singleton(value);
}
return singleton_;
}
int main() {
Singleton* singleton1 = Singleton::get_instance("FOO");
Singleton* singleton2 = Singleton::get_instance("Bar");
//如果values相同,说明单例生效了
cout << singleton1->value() << endl;
cout << singleton2->value() << endl;
return 0;
}
如果同时有多个线程请求获取单例,那么上述实现就不安全了。因此需要进行线程同步,即使用线程安全单例。
该模式的优缺点
- 优点
- 你可以保证一个类只有一个实例。
- 你获得了一个指向该实例的全局访问节点。
- 仅在首次请求单例对象时对其进行初始化。
- 缺点
- 违背了单一职责原则。该模式同时解决了两个问题
- 该模式在多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象。
- 单例模式可能掩盖不良设计, 比如程序各组件之间相互了解过多等。