【设计模式】单例模式的三种形式 C++ 创建型模式

本文深入解析单例模式的实现原理,包括普通单例、饿汉单例和懒汉单例三种模式,通过C++代码示例展示如何确保类的唯一实例,并探讨不同模式下资源利用与响应速度的权衡。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单例模式顾名思义就是只能生成一个示例。其实在我个人不太成熟的理解上来说,单例模式的作用等同于在所有的成员变量和成员类前面加上一个“static”。所有调用这个类生成的实例都是同一个,因此我认为等同于将所有的类资源变成静态资源。

既然要有且仅有生成一个实例,那么我们需要做的就两件事。

1.将所有能够生成类实例的途径全部堵上,例如构造函数、拷贝构造函数私有化,外部无法访问也就无法通过他们生成实例了。

2.既然无法在外部生成类的实例,那么我们就需要想办法在类的内部生成类的实例,并且能够被我们所调用。

综上所诉,就可以得到一个简单的单例模式的例子了:

#include <iostream>
#define debug
class Single{
	private:
		Single(){
			this->test = 0;
		}
		Single(const Single&){;}
		Single& operator = (const Single&){;}
		static Single* instance;
	public:
		static Single* getInstance();
		int test;
};

Single* Single::instance = NULL;
Single* Single::getInstance(){
	if(instance == NULL){
		instance = new Single();
	}
	return instance;
}

int main(){
	Single* single_1 = Single::getInstance();
	Single* single_2 = Single::getInstance();
	
	if(single_1 == single_2)
		std::cout << "single_1与single_2的地址一致" << std::endl << std::endl;
	
	#ifdef debug
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	single_1->test = 5;
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	single_2->test = 10;
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	#endif
	std::cin.get();
	return 0;
}

运行结果:

为了说明单例模式是成功的,代码先比较了“两个实例”的地址,程序输出结果表明地址是一致的。我们还在下面先后修改了single_1和Single_2实例中test的值,输出结果表明,sing_1和sing_2中test的值始终保持一致,也证明了仅生成了一个实例。

单例模式中还有一种称作是饿汉单例模式的分类,饿汉单例模式简单粗暴,在类内部直接生成一个实例,封堵其余生成实例的途径,以下是例子:

#include <iostream>
#define debug
class Single_hunger{
	private:
		Single_hunger(){
			this->test = 0;
		}
		Single_hunger(const Single_hunger&){;}
		Single_hunger& operator = (const Single_hunger&){;}
		static Single_hunger* instance;
	public:
		static Single_hunger* getInstance();
		int test;
};

Single_hunger* Single_hunger::instance = new Single_hunger();
Single_hunger* Single_hunger::getInstance(){
	return instance;
}

int main(){
	Single_hunger* single_1 = Single_hunger::getInstance();
	Single_hunger* single_2 = Single_hunger::getInstance();
	
	if(single_1 == single_2)
		std::cout << "single_1与single_2的地址一致" << std::endl << std::endl;
	
	#ifdef debug
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	single_1->test = 5;
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	single_2->test = 10;
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	#endif
	std::cin.get();
	return 0;
}

可以看出,饿汉单例和普通的单例模式的区别在于,普通单例的实例是在getInstance()函数中生成的,当且仅当访问这个函数的时候才会生成实例;而饿汉模式是在类的内部实现的,因此一开始就已经存在了这个实例,因此,饿汉模式的调用速度和反应速度更快,但是资源利用效率和系统加载时间上就表现比较差了。

同时,饿汉单例模式无需考虑多线程的影响,如果系统采用了多线程,那么普通的单例模式就不能满足系统的需求了。因为我们要创建实例,在多线程访问的情况下,我们需要加锁,这种模式叫懒汉模式,一下是例子:

#include<iostream>
#define debug
class Single_lazy{
	private:
		Single_lazy(){
			this->test = 0;
		}
		static Single_lazy* instance;
		Single_lazy(const Single_lazy&){;}
		Single_lazy& operator = (const Single_lazy&){;}
		static bool lock;
		
	public:
		int test;
		static Single_lazy* getInstance();
};
Single_lazy* Single_lazy::instance = NULL;
bool Single_lazy::lock = false;
Single_lazy* Single_lazy::getInstance(){
	if(instance == NULL){
		/* 没有生成示例,首先上锁 */
		if(!lock){
			lock = true;
			/* 第二次检测是否已经生成示例 */
			if(instance == NULL){
				instance = new Single_lazy();
			}else;
			lock = false;
		}else; 
	}else;
	return instance;
}

int main(){
	Single_lazy* single_1 = Single_lazy::getInstance();
	Single_lazy* single_2 = Single_lazy::getInstance();
	
	if(single_1 == single_2)
		std::cout << "single_1与single_2的地址一致" << std::endl << std::endl;
	
	#ifdef debug
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	single_1->test = 5;
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	single_2->test = 10;
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	#endif
	std::cin.get();
	return 0;
} 

懒汉模式在原有的普通单例模式的基础上增加了锁,保证有且仅有一个线程能够创建实例,避免了多线程导致创建多个实例出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值