设计模式之单例模式

1. 单例模式

1.1 简介

在实际项目开发中肯定会有这么一种情况,一个类只能有一个对象被创建,如果有多个对象的话, 可能会导致状态的混乱和不一致。这种情况下,单例模式是最恰当的解决办法。 它有很多种实现方式,各自的特性不相同,使用的情形也不相同。

1.2 特点

1.提供了一个对对象的全局访问指针

2.在不影响单例类的客户端的情况下允许将来有多个实例,通过接口获得

3.确保一个类只有一个实例被建立 ,不能额外创建一个新的对象

1.3 应用场景

  • 读取配置文件,读取的配置文件都是公用的,只能有一个示例去操作文件

  • 数据连接线程池,多线程的时候.

  • 应用程序的日志应用,一般都可以使用单例模式来实现,只能又一个示例去操作文件

1.4 实现思路

1)将构造函数的访问权限修改为private或protected,不允许类的外部来创建对象

2)用一个静态成员指针指向创建的对象

3)提供一个静态成员函数,获得这个对象的首地址

2. 懒汉式

先上代码:

#include <iostream>
using namespace std;

// 作者博客
static string myblog = "https://www.cnblogs.com/wanghongyang/";

class singelton {
private:
	singelton() { ; }
	static singelton *single;
public:
	static singelton *get_instance();
};

// 静态变量初始化
singelton* singelton::single = NULL;

singelton * singelton::get_instance()
{
	if (single == NULL) {
		single = new singelton;
	}
	return single;
}

int main()
{
	singelton* s1 = singelton::get_instance();
	singelton* s2 = singelton::get_instance();
	if (s1 == s2)
	{
		cout << "s1==s2" << endl;
	}
	else {
		cout << "s1!=s2" << endl;
	}
	return 0;
}

可以看到,思路是非常简单的,所谓懒汉式,就是当你用的时候,我才初始化

但是这会带来一个问题,大家思考一下,如果添加了析构函数将会怎么样,如何解决?

参考代码如下

class singelton {
private:
	singelton() { ; }
	static singelton *single;
public:
	static singelton *get_instance();
	~singelton() {
		cout << "~singelton()" << endl;
		if (single != NULL)
		{
			delete single;
		}
	}
};

// 静态变量初始化
singelton* singelton::single = NULL;

singelton * singelton::get_instance()
{
	if (single == NULL) {
		single = new singelton;
	}
	return single;
}

int main()
{
	singelton* s1 = singelton::get_instance();
	singelton* s2 = singelton::get_instance();
	if (s1 == s2)
	{
		cout << "s1==s2" << endl;
	}
	else {
		cout << "s1!=s2" << endl;
	}
	delete s1;
	return 0;
}

可以看到,会出现不断调用析构函数的现象,因为singelton为用户自定义的类,delete会默认调用该类的析构函数

运行结果:

image-20210815114706320

2.1 解决方案

自定义一个类,用于释放空间

class singelton {
private:
	singelton() { ; }
	static singelton *single;

	class DeleteSpace {
	public:
		DeleteSpace();
		~DeleteSpace();
	};

	static DeleteSpace ds; // 释放堆区空间的类对象

public:
	static singelton *get_instance();
};

// 静态变量初始化
singelton* singelton::single = NULL;

singelton * singelton::get_instance()
{
	if (single == NULL) {
		single = new singelton;
	}
	return single;
}

singelton::DeleteSpace singelton::ds; // 初始化释放空间的静态类

singelton::DeleteSpace::DeleteSpace() { ; }
singelton::DeleteSpace::~DeleteSpace() {
	cout << "~DeleteSpace()" << endl;
	if (single != NULL)
	{
		delete single;
	}
}

int main()
{
	singelton* s1 = singelton::get_instance();
	singelton* s2 = singelton::get_instance();
	if (s1 == s2)
	{
		cout << "s1==s2" << endl;
	}
	else {
		cout << "s1!=s2" << endl;
	}

	return 0;
}

这个例子的原理就是,当程序运行结束,堆区释放的时候,会自动调用析构函数,析构单例类,这样做就不需要手动的去释放单例类

运行结果

image-20210815155954306

2.2 优缺点

优点:

在使用的时候,才会分配内存,创建对象

缺点:

在多线程使用,会出现创建多个对象的问题,线程不安全

2.3 线程安全示例代码

在刚刚的那种懒汉式的方法中,如果有多线程的情况,可能会大家都以为自己是第一个创建单例类,因此有可能创建多个单例类,为了保证线程安全,下面演示线程不安全的代码

image-20210815180411067

image-20210815180426525

结果可以看到,调用了三次构造函数

image-20210815180452770

解决办法

添加互斥锁来解决

image-20210815180521228

image-20210815180532387

3. 饿汉式

在单例类定义的时候就进行了实例化。---在类定义的时候,分配空间

image-20210815180739253

3.1 优缺点

优点: 线程安全

缺点:还没有正式使用,就分配了内存空间,浪费了内存

posted @ 2021-08-15 18:11  进击的汪sir  阅读(135)  评论(0编辑  收藏  举报