一天一个设计模式——单例模式

437 阅读2分钟

参考:refactoringguru.cn/design-patt…

意图

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

问题

单例模式解决了两个问题

  1. 保证一个类只有一个实例。每次调用普通构造函数都会返回一个新对象。而采用单例模式可以保证每次创建新对象时,会返回一个已创建的对象。
  2. 为该实例提供一个全局访问节点。和全局变量一样, 单例模式也允许在程序的任何地方访问特定对象。 但是它可以保护该实例不被其他代码改写。

解决方案

单例模式的实现包含以下两个步骤:

  1. 将默认构造函数设为私有, 防止其他对象使用单例类的 new运算符。
  2. 新建一个静态构建方法作为构造函数。 该函数会 “偷偷” 调用私有构造函数来创建对象, 并将其保存在一个静态成员变量中。 此后所有对于该函数的调用都将返回这一缓存对象。

单例模式结构

单例模式结构

  1. 单例 (Singleton) 类声明了一个名为 get­Instance获取实例的静态方法来返回其所属类的一个相同实例。该方法是获取单例对象的唯一方式。

代码实现

#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;
}

如果同时有多个线程请求获取单例,那么上述实现就不安全了。因此需要进行线程同步,即使用线程安全单例

该模式的优缺点

  1. 优点
    • 你可以保证一个类只有一个实例。
    • 你获得了一个指向该实例的全局访问节点。
    • 仅在首次请求单例对象时对其进行初始化。
  2. 缺点
    • 违背了单一职责原则。该模式同时解决了两个问题
    • 该模式在多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象。
    • 单例模式可能掩盖不良设计, 比如程序各组件之间相互了解过多等。