设计模式之单例设计模式

单例模式(Singleton)

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

单例特点:

1 在任何情况下,单例类永远只有一个实例存在。

2 单例需要有能力为整个系统提供这一唯一实例。

示例:打印机,任务管理器等。

分为两种:

饿汉模式懒汉模式

饿汉模式:

实例对象在程序启动时就已经创建了

理解:太饿了,等不及要吃了

懒汉模式:

实例对象只有在第一次使用时才会被创建

理解:太懒了,要用了,才做吃的

饿汉模式的优点是线程安全,因为,不需要担心多个线程同时创建实例导致的线程安全问题。但是,它的缺点是可能会浪费内存,因为实例对象在程序启动时就已经创建了,即使在程序运行过程中没有使用它。

懒汉模式的优点是节省内存,因为实例对象只有在第一次使用时才会被创建。但是,它的缺点是可能会存在线程安全问题,因为多个线程可能同时访问实例对象,导致创建多个实例的问题。

对于一个类只能创建一个对象,对应的就是设计模式当中的单例模式

思路:

  1. 限制构造函数(只要禁用析构,即将其私有化,所有构造都不可以在类外用了)和析构函数(其实本质来说限制析构函数就可以了),说白了就是将构造、析构定义为私有
  2. 提供一个公有的函数访问构造函数(此时构造【私有的】只能在类里面使用,所以应该在类中创建对象),该公有函数需要限制访问次数(),且该函数不需要对象就能访问(因此定义为静态函数,其返回值为指针和引用,不能返回栈区內存,可以返回堆区(new)和静态全局区(static))
  3. 既然返回值为堆区或者静态全局区,则接收该申请的內存要么静态变量或者堆区new的內存;

举例实现:

注:格式其实应该是类声明在头文件.h中,类实现在.cpp中,此处是为了例子更容易理解

懒汉模式:

#include<iostream>
using namespace std;
//单例类
class Singleton
{
public:
	/*此处的返回值可以是类的指针类型或者引用类型,
	但绝对不能是类类型,否则会调用拷贝,此时对象会增加变为2个*/
	static Singleton* GetSingleton()
	{
         //此处为懒人模式
		//计数器加1(使用该对象的人+1)
		++count;
		//判断指针是否为空
		if (nullptr == pSingleton)
		{
			//选择返回堆区內存   释放会比较麻烦 
			pSingleton = new Singleton;
			
		}
		//返回值为指针类型或者引用类型,不能返回栈区的变量,只能返回堆区或者静态全局区的变量
		return pSingleton;
	}
	//单例模式对象的释放是不可以在析构里面的,否则会造成递归调用析构,所以要自己写释放函数
	void DeleteSingleton()
	{
		/*自己写也需要注意,一般来叔,如果存在好几个地方都在用我的单例对象,此
		时其中任意一个单例內存释放了,其余在使用的【因为本质就一个对象】全部会
		释放掉。

		为了解决此问题现在优化:
		新增一个计数器(静态数据成员,所有对象共享,属于类),当其为0时,调用释放函数可以释放,
		不为0时,则不可以释放
		*/
		//计数器减1(使用该对象的人-1)
		--count;
		//正真释放內存
		if (0 == count)
		{
			delete pSingleton;
			//指针置空(delete释放指针所指內存后,一定要置空,避免出现野指针,这里的置空原因是为了下一次单例对象创建使用)
			pSingleton = nullptr;
		}
	}
private:
	//构造函数私有,主要用于对对象初始化
	Singleton()
	{
	}
	//将析构定义为私有成员,则类外部所有构造函数都不可以用,即类外不可以创建对象,所以析构私有是关键
	~Singleton()
	{
	}
	//声明静态数据成员,用于接收该对象的地址
	static Singleton *pSingleton;
	//计数器,用于做正真释放判断
	static int count;
};

//静态数据成员必须要初始化
Singleton *Singleton::pSingleton = nullptr;
int Singleton::count = 0;

//主函数使用
int main()
{
	//报错,因为构造不可用
	//Singleton A;

	//刚开始没对象,用函数创建对象
	Singleton *B = Singleton::GetSingleton();

	/*拷贝构造虽然没有被定义为私有,但析构函数定义为私有了,
	准确来说,因为析构被私有,类外不可访问,导致所有构造在类
	外都被禁用了【因为析构和构造必须成对】*/
	//Singleton C = *B;

	//用户D也使用 
	Singleton *D = Singleton::GetSingleton();

	//注意:要保证D和B一者不想用了,另一方还可以继续使用
	//请看类成员函数DeleteSingleton()的定义

	cout << "D指向对象的地址:" << D << endl;
	//D不想用了,B应该还能使用
	cout << "D不用了" << endl;
	D->DeleteSingleton();
	//此时D指向內存被释放,指针要置空
	D = nullptr;
	cout << "B指向对象的地址:" << B << endl;
	//B也不想用了,地址置空,现在就2人在用
	cout << "B不用了" << endl;
	B->DeleteSingleton();
	//此时B指向內存被释放,指针要置空
	B = nullptr;
	cout << "B指向对象的地址:" << B << endl;

	return 0;
}

饿汉模式:

#include<iostream>
using namespace std;

class Singleton
{
public:
	static Singleton* GetSingleton()
	{
		//饿汉模式
		//此处比较简单 编译时其实就已经创建了新对象,后面再运行都是第一次创建的对象
		//其次并不需要考虑释放的问题,静态局部变量程序执行结束,系统自动回收內存
		//內存在静态全局区
		static Singleton singleton;
		return &singleton;
	}
private:
	//析构、构造禁用
	Singleton()
	{
	}
	~Singleton()
	{
	}
};

int main()
{
	//刚开始没对象,用函数创建对象
	Singleton *B = Singleton::GetSingleton();

	//用户D也使用 
	Singleton *D = Singleton::GetSingleton();

	//注意:要保证D和B一者不想用了,另一方还可以继续使用,但这里和上面不太一样
	//此时实现原理是,其实它只要程序在运行中,该对象其实一直存在

	cout << "D指向对象的地址:" << D << endl;
	//D不想用了,B应该还能使用
	cout << "D不用了" << endl;
	//此时D指向內存并未释放,但要回收访问的权限,所以指针要置空
	D = nullptr;
	cout << "B指向对象的地址:" << B << endl;
	//B也不想用了,地址置空,现在就2人在用
	cout << "B不用了" << endl;
	//此时B指向內存并未释放,但要回收访问的权限,所以指针要置空
	B = nullptr;
	cout << "B指向对象的地址:" << B << endl;
	cout << "其内存一直都在:" << Singleton::GetSingleton() << endl;
	return 0;
}

例题:
实现一个类,保证该类只能创建一个对象 点类Point,静态成员输出count的值,用成员函数输出点的信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值