C++设计模式——单件模式(singleton pattern)

一、原理讲解

由于单件模式也称为单例模式,分为懒汉式单例模式和饿汉式单例模式,两者主要区别是类对象的返回是在编译时创建?还是调用时才创建?其中,懒汉式单例模式是在程序调用时才创建,而饿汉式单例模式是在程序编译时期创建类实例。懒汉式是非线程安全的,而饿汉式是线程安全的。因为项目中用懒汉式比较多,所以本文主要总结的是懒汉式单例模式。饿汉式单例模式可以参考博主这篇文章:Qt5.9中单例模式用法(饿汉模式、懒汉模式,C++语言)

1.1意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

1.2应用场景

  • 当一个类只有一个实例,而且客户端可以从一个众所周知的访问点访问它时;
  • 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无须更改代码就能使用一个扩展的实例时;

1.3结构图(UML图)

C++设计模式——单件模式(singleton pattern)_第1张图片

1.4代码实现步骤

a1 定义一个具体类Singleton,将构造函数变成私有;
a2 定义一个私有静态成员变量singleton和共有静态函数getSingleton,函数getSingleton返回类Singleton的静态成员变量singleton,从而获取到该类唯一实例。

二、实现代码

2.1 简单版单例模式

Singleton.cpp

#include 

using namespace std;

class Singleton {
     
public:
	static Singleton* getSingleton() {
     
		if (singleton == nullptr) {
     
			singleton = new Singleton();			
		}
		return singleton;
	}
	void show() {
      cout << "Singleton" << endl; }
	
private:
	static Singleton *singleton;

	Singleton(){
     }
	Singleton(Singleton&) = delete;
	Singleton& operator=(Singleton&) = delete;
};
Singleton *Singleton::singleton = nullptr;

void doSingletonPattern()
{
     
	Singleton::getSingleton()->show();
}

mian.cpp

#include 

extern void doSingletonPattern();

int main()
{
     
	doSingletonPattern();

	system("pause");
	return 1;
}

C++设计模式——单件模式(singleton pattern)_第2张图片

2.2模板版单例模式

Singleton.cpp

template<class T>
class Singleton {
     
public:
	static T& getSingleton() {
     
		static T singleton; //多次调用只会实例一次
		return singleton;
	}	

protected:
	Singleton() {
      cout << "Singleton::Singleton()" << endl; } //为了派生类继承后,实例的时候能够调用构造函数

private:	
	Singleton(Singleton&) = delete;
	Singleton& operator=(Singleton&) = delete;
};

class A : public Singleton<A> {
     
public:
	friend class Singleton<A>; //为了基类能够调用派生类private成员函数和变量

	void showA() {
      cout << "A::showA()" << endl; }

private:
	A(A&) = delete;
	A& operator=(A&) = default;
	A():Singleton<A>(){
      cout << "A::A()" << endl; };
};

void doSingletonPattern()
{
     
	A &a1 = Singleton<A>::getSingleton();
	A &a2 = Singleton<A>::getSingleton();
	a1.showA();
	a2.showA();
	cout << "a1==" << &a1 << "\ta2==" << &a2 << endl;
}

main.cpp

#include 

extern void doSingletonPattern();

int main()
{
     
	doSingletonPattern();

	system("pause");
	return 1;
}

C++设计模式——单件模式(singleton pattern)_第3张图片

三、总结

3.1实现总结

3.1.1简单版单例模式

简单版的单例模式实现方式是通过编译时创建一个静态指针,调用时new创建一个动态对象,然后返回该静态指针实现对象获取,为了保证全局唯一,需要将构造函数变为私有,并且禁止拷贝构造和赋值函数。

3.1.2模板版单例模式

模板版单例模式是通过提取简单版单例模式公共部分总结成一个框架,后面任何继承该基类的类都是单例模式,实现了单例模式的模板化。实现要点是在返回函数内,通过创建一个静态指针并且指向一个new创建的对象空间,然后返回该对象指针。由于在基类实例化派生类对象,故基类需要调用派生类的构造函数,由于派生类构造函数是私有的,所以需要在派生类中将该基类声明为私有的;同时派生类调用构造函数的时候,需要调用基类构造函数,所以基类构造函数必须要声明为受保护的类型以便被派生类继承和调用;

3.2简单版和模板版单例模式差异

两者主要区别在实例化对象方式上。简单版直接实例化对象然后返回该静态指针,直接调用该返回的指针即可;而模板版则是在基类模板实例化派生类(派生类将自己的类型传入基类),由于基类要调用派生类构造函数,所以需要在派生类中将基类声明为友元类;而派生类调用构造函数时,需要先调用基类构造函数,故需要继承基类构造函数,所以基类构造函数必须声明为protected。
总之一个主要逻辑就是:基类实例化派生类对象——>基类需要调用派生类构造函数(派生类中将基类声明为友元类)——>派生类要先调用基类构造函数(基类构造函数声明为protected)
最后,由于该方法是非线程安全的,所以只能用于单线程,而不能用于多线程中,如果需要在多线程也用该单例模式这需要加锁保护,线程安全的后面再另开文章讨论总结啊。

四、参考内容

C++中operator关键字(重载操作符)
c++设计模式:单件模式(Singleton Pattern)
单件模式的C++实现)
C++ 单例模式总结与剖析(经典))
陈建忠设计模式(参考:哔哩哔哩C++设计模式!!!)
Erich Gamma,Richard Helm.《设计模式 可复用面向对象软件的基础》[M].机械工业出版社,2019:

你可能感兴趣的:(设计模式,c++,设计模式,单件模式,单例模式,懒汉模式)