设计模式之---【Singleton(单例模式)】

      Singleton(单例模式)也有叫单件模式,是创建型模式的一种,也是最简单最常用的模式之一。

      注意设计模式的学习并不能像学习语法或者公式那样死记硬背,因为各种模式是人们在工程实践中总结出来的,一定要带着应用场景去研究。或者说设计模式是一种思想,在面向对象的程序设计(Java、C++等)里讨论设计模式的比较多,C语言编程谈论设计模式比较少见,但是C语言里就不能实现面向对象的程序设计吗?显然不是,我们可以使用结构体仍然可以实现,只不过像Java和C++它们的语言特性就是为了面向对象而设计的。

       单例模式,它的最主要特征是只有一个实例。在什么情况下使用呢?比如,我想定义一个全局变量,将这个变量的从一个类传到另外一个类,当然定义一个全局变量是可以的,但是如果代码里采用大量的全局变量,你自己都会觉得这样是不是太low了,是的显然破坏了C++等面向对象语言的结构性。所以,你可能会想到把这样变量用一个类包起来,但是问题来了,你怎么去访问这个类里面的变量,你访问的时候就需要实例化,然后给那个变量赋值,再然后在另外的一个类里获取值,又要实例化,显然两次实例化,赋值和获取值并不是同一个实例,显然并不能达到目的;你会不会想能不能把第一次实例化那个对象保存起来,访问的时候就用这个保存下来的对象访问,用什么方式保存呢?全局的?又回到原点了。。。这样的问题前辈们肯定都尝试过,所以才总结成现在的单例模式

    那么单例模式到底实现了什么功能?举例:

#include "stdafx.h"
#include<iostream>
using namespace std;
int x = 0;
class A {
public:
	int a;
};
class B {
public:
	B() {
		cout << "BBB" << endl;
	}
	static int b;
	B & operator=(const B & b)
	{
		this->b = b.b;
	}
};
int B::b = 0;//类里的静态变量需要在外面定义
int main()
{
	
	A a1;
	a1.a = 10;
	//A的成员变量的a的值赋给x
	x = a1.a;
	//B类的成员变量b来接收x变量的值
	B b1;
	b1.b = x;
	B b2;
	int ret = b2.b;
	cout << "结果" << ret << endl;
	return 0;

}

这就是上面low的方法,x为全局变量。

下面就用经典的单列模式写法:

//#pragma once
#ifndef _SINGLETON_H_ 
#define _SINGLETON_H_ 
#include <iostream> 
using namespace std;
/*********************1.经典定义方法*****************************/

class CSingleton
{
public:
	static CSingleton* Instance()
	{
		if (_instance == NULL)
		{
			_instance = new CSingleton();
		}
		return _instance;
	}
private:
	CSingleton(){}
	static CSingleton* _instance;
};
CSingleton* CSingleton::_instance = NULL;

/*********************1.经典定义方法*****************************/
#endif //~_SINGLETON_H_

注意几点:

1.构造函数需要定义成private或者protected,是因为类外想要实例化时会提示错误,只能以下面的方式:

补充:CSingleton sgn;    因为实例化的时候自动调用构造函数,但是构造函数为私有或者保护类型,因此会报错。

CSingleton* sgn1 = CSingleton::Instance();
CSingleton* sgn2 = CSingleton::Instance();

可以单步调试,第一次会调用_instance = new CSingleton();第二次直接跳过,直接返回_instance,这样保证两次访问的地址是相同的。

2.CSingleton* Instance()需要定义为static,否则类外直接调用会报错。

 

3.CSingleton* _instance也要声明成static,否则在类外不能定义(在类外,主要是为了程序一启动就对_instance初始化为NULL)

补充:静态成员属于类,并不属于类的对象,它可以理解为类里的全局变量。

另外,静态成员变量需要在类外定义(当前文件里),否则无法访问,会报错“error LNK2001: 无法解析的外部符号”;

这样磕磕绊绊达到了和“全局变量一样”效果的类,这就相当于造了一个模子,使用的时候,就把想定义的变量,加到这个类里面,用这唯一的一个实例(事实上用_instance指针去访问)。面向对象语言就是这样,看起来比全局变量优雅吧。

懒汉式和饿汉式

懒汉式:就是上面这种,为啥叫懒汉式,是说这种单例模式太懒了,程序员调用的时候才实例化

而下面的方式是饿汉式:还没等程序员要呢,就自己先实例化了,是不是很饥渴。

#pragma once
#include<iostream>

class CSingleton
{
public:
	static CSingleton* Instance()
	{
		return _instance;
	}
private:
	CSingleton() {}
	static CSingleton* _instance;
};
CSingleton* CSingleton::_instance = new CSingleton();

程序启动的时候就CSingleton* CSingleton::_instance = new CSingleton();实例化了,每次调用直接返回 _instance即可。

特点与选择:

由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。

在访问量较小时,采用懒汉实现。这是以时间换空间。

【参考】https://www.cnblogs.com/guxuanqing/p/5876873.html

 

其他知识点:

1.多线程的单列模式处理:参考:https://www.cnblogs.com/dupengcheng/p/7205527.html

这篇博客有个地方,我觉得有个地方:

这个锁应该放在if语句外面,要不然两个线程还是会实例化两次。

2.单列模式的析构处理:参考:https://www.cnblogs.com/sixbeauty/p/3790693.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值