初识设计模式1:单例模式(不考虑多线程)

初识设计模式1:单例模式

一、什么是单例模式?

在整个进程中,或者说是在整个工做过程当中,只容许有一个实例对象的存在 。这个实例对象可以完成所有工做过程所须要的属性和方法。因此不须要再有其余的实例!这个单例模式每每运用在某些资源受限的场景 中,和操做系统的 “互斥信号量” 很是类似。好比打印机,咱们限定只有一台打印机(资源受限),而后就得防止其余人另外开辟资源来实例化第二个打印机(能够理解为大家的资金只预算了这一台打印机,若是超预算,你得破产!)。而且这个资源不光是给一我的使用的,它是一个全局的访问点 !而且 一个类只能有这一个实例ios

二、如何实现单例模式?

这个问题咱们分解成几个小的问题来看:c++

2.一、如何保证一个惟一的实例?

实例如何而来?在面向对象编程中,对象实例所有来自构造方法,因此只须要隐藏构造方法 ,让其余用户没法去自行实例化便可。那么这个实例就会是属于这个类的通常实例 。既然这个实例是属于类的,那么说明这个实例是一个静态成员程序员

2.二、如何获取这个惟一的实例?

只须要开放一个静态接口(由于实例也是静态的)。这个接口负责检查实例是否已经被建立,如若被建立就直接返回已经存在的实例,不然实例化一个给属于类的私有单例。编程

2.三、代码示例:

#include <iostream>
using namespace std;

class Singleton {
private:
	static Singleton* MySingleInstance;
	Singleton() { cout << "单一实例已经被建立!" << endl; }
public:
	static Singleton* GetMySingleInstance() {
		if (nullptr == MySingleInstance)
			MySingleInstance = new Singleton();
		return MySingleInstance;
	}
};
Singleton* Singleton::MySingleInstance = nullptr;

int main() {
	Singleton* instance1 = Singleton::GetMySingleInstance();
	Singleton* instance2 = Singleton::GetMySingleInstance();
	if (instance1 == instance2)
		cout << "这是一个单例模式!" << endl;
	else
		cout << "这不是一个单例模式!" << endl;
	return 0;
}

2.四、结果展现:

在这里插入图片描述

2.五、作个小结:

这是一种典型的《懒汉模式》的实现方式,由于这个单例,是在第一次使用到的时候才去初始化的!若是是《饿汉模式》,则是在尚未须要使用单例的时候就已经完成初始化了!其实要想实现《饿汉模式》很是简单,只须要把咱们的单例从一个对象指针变成一个静态的成员变量便可!以下:设计模式

#include <iostream>
using namespace std;

class Singleton {
private:
	static Singleton MySingleInstance;
	Singleton() { cout << "单一实例已经被建立!" << endl; }
public:
	static Singleton* GetMySingleInstance() { return &MySingleInstance; }
};
Singleton Singleton::MySingleInstance;// 饿汉模式,这个类一存在这个单例就被建立!

int main() {
	Singleton* instance1 = Singleton::GetMySingleInstance();
	Singleton* instance2 = Singleton::GetMySingleInstance();
	if (instance1 == instance2)
		cout << "这是一个单例模式(饿汉模式)!" << endl;
	else
		cout << "这不是一个单例模式!" << endl;
	return 0;
}

《饿汉模式》实现的单例模式运行结果以下:
在这里插入图片描述安全

那么饿汉模式和懒汉模式在具体应用上有何区别呢?查阅资料得知有线程安全方面的问题,可是咱们这里只是初探,就不研究线程安全了!我我的理解来讲,线程安全应该相似于《操做系统》里面互斥型信号量在同步访问的时候的线程保护吧,我没有仔细研究,若有说错的地方,还请各位高手指出markdown

三、关于单例模式(懒汉)的资源回收问题

众所周知,懒汉模式下实现的单例,须要依赖动态内存分配。这种分配在堆空间的资源,必定是须要程序员经过代码来进行资源回收的!众所周知,只有尽可能完美作到RAII原则的c++程序员才是一个优秀的c++程序员!咱们该如何处理进程结束后的单例资源呢?框架

3.一、使用析构函数,自行delete释放

错误代码以下:ide

class Singleton {
private:
	static Singleton* MySingleInstance;
	Singleton() { cout << "单一实例被建立!" << endl; }
public:
	static Singleton* GetMySingleInstance() {
		if (nullptr == MySingleInstance)
			MySingleInstance = new Singleton();
		return MySingleInstance;
	}
	~Singleton() { 
		delete Singleton::MySingleInstance; 
		// delete 以后调用析构函数,而后析构函数又调用 delete … 循环往复!
		cout << "单例资源被释放" << endl;
	}
};
Singleton* Singleton::MySingleInstance = nullptr;// 饿汉模式,这个类一存在这个单例就被建立!

int main() {
	Singleton* instance = Singleton::GetMySingleInstance();
	delete instance;
	return 0;
}

这种操做没法完成析构,甚至还会陷入死循环带来程序崩溃 !缘由我在上面的注释里写到了:delete 以后调用析构函数,而后析构函数又调用 delete … 循环往复!函数

那是否这种调用析构函数的方式不可行呢?其实不是的!

如何避免这个已经被delete后的对象,再次进入属于它的析构方法呢?只须要进行一次标记就好:

#include <iostream>
using namespace std;

class Singleton {
private:
	static Singleton* MySingleInstance;
	Singleton() { cout << "单一实例被建立!" << endl; }
public:
	static Singleton* GetMySingleInstance() {
		if (nullptr == MySingleInstance)
			MySingleInstance = new Singleton();
		return MySingleInstance;
	}
	~Singleton() { 
		if (nullptr != MySingleInstance) {// 检测标记
			Singleton::MySingleInstance = nullptr;// 作上标记
			delete Singleton::MySingleInstance;
		}
		cout << "单例资源被释放" << endl;
	}
};
Singleton* Singleton::MySingleInstance = nullptr;// 饿汉模式,这个类一存在这个单例就被建立!

int main() {
	Singleton* instance = Singleton::GetMySingleInstance();
	delete instance;
	return 0;
}

析构后效果展现:

在这里插入图片描述

3.二、可否让系统自行在进程结束以后,完成单例资源的回收呢?

众所周知,静态对象,在发生类建立的进程 结束后,会系统自动回收资源,这个资源的回收也是调用了静态对象的析构方法!因而咱们能够利用这个特色,让一个单例伴随一个静态对象,如何才能实现这点呢?只须要写一个内部类,建立一个内部类对象,这个对象是和成员属性、成员方法同级别的,是属于外部类的实例的!也就是属于单例的一个伴随对象!咱们只须要让这个对象成为一个静态对象,那么就能够在实例工做结束后,在它的析构中完成对实例的析构!

系统自动回收的代码框架:

#include <iostream>
using namespace std;

class Singleton {
private:
	static Singleton* MySingleInstance;
	Singleton() { cout << "单一实例被建立!" << endl; }

	class GarbageCollector {
	public:
		~GarbageCollector() {
			if (nullptr != Singleton::MySingleInstance) {
				Singleton::MySingleInstance = nullptr;// 作上标记
				delete Singleton::MySingleInstance;
			}
			cout << "单例资源被释放" << endl;
		}
	};
	static GarbageCollector MyGC;
public:
	static Singleton* GetMySingleInstance() {
		if (nullptr == MySingleInstance)
			MySingleInstance = new Singleton();
		return MySingleInstance;
	}
};
Singleton* Singleton::MySingleInstance = nullptr;// 饿汉模式,这个类一存在这个单例就被建立!
Singleton::GarbageCollector Singleton::MyGC;

int main() {
	Singleton* instance = Singleton::GetMySingleInstance();
	return 0;
}

系统自动回收单例资源的结果展现:

在这里插入图片描述

四、一个具体的应用场景:

假设须要对一个单例资源:打印机进行处于单例模式下的工做,个人代码以下:

#include <iostream>
using namespace std;

class printing {
public:
	static printing* GetPrintingInstance() {
		if (nullptr == MyInstance)
			MyInstance = new printing();
		return MyInstance;
	}
	class Garbo {
	public:
		~Garbo(){
			if (nullptr != printing::MyInstance) {
				printing::MyInstance = nullptr;
				delete printing::MyInstance;
				cout << "打印机实例注销" << endl;
			}
		}
	};
	static Garbo MyGarbo;
	static int number;
	void doPrint() { 
		cout << "打印机正在打印第:" << number << " 个打印任务" << endl; 
		number++;
	}
private:
	printing() { cout << "打印机实例启动" << endl; }
	static printing* MyInstance;
};
int printing::number = 1;
printing* printing::MyInstance = nullptr;
printing::Garbo MyGarbo;// 默认构造,初始化 MyGarbo

void doIt() {
	printing* util = printing::GetPrintingInstance();
	int task = 20;
	while (task--) 
		util->doPrint();
}

int main() {
	doIt();
	return 0;
}

应用结果展现以下:

在这里插入图片描述

写在后面的话:

本人也没有在课堂上学过《设计模式》,也是在课余时间里作项目遇到了。深感设计模型、面向对象思想,在大型软件设计中的做用!他们都能大大提升代码的可复用性,减少工做量、减少代码冗余,增长软件的稳定性!因为没有正式学习设计模式,因而本文标题也只敢写:《初始设计模式》,写的不对或者很差的地方,还请各位前辈大佬提出,欢迎指正!!!!

相关文章
相关标签/搜索