前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我用过的设计模式(2)-- 单例模式

我用过的设计模式(2)-- 单例模式

原创
作者头像
看、未来
修改2021-02-25 10:15:23
2940
修改2021-02-25 10:15:23
举报
在这里插入图片描述
在这里插入图片描述

单例模式

什么是单例模式呢?

在项目中,有些类是需要对它们进行“计划生育”的,即这个类只能有一个实例,如果出现多个实例则会有数据不一致的风险。

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

这个模式的类,叫单例类,所以类图我就不画了吧。

单例模式的应用场景举例:牵扯到数据问题,数据库首当其冲,缓存自然也跑不了。


代码实现

代码语言:txt
复制
//这里是.h文件
//老板类单例
class Single_Boss
{
public:
    static Single_Boss *instence();//获取数据库单例
//重点在这个函数
	void run();
private:
    Single_Boss();
    ~Single_Boss();
    char *errmsg;

    static Single_Boss *Boss;//实例
};
代码语言:txt
复制
//源文件

Single_Boss *Single_Boss::Boss= NULL;

Single_Boss::Single_Boss()
{
    cout << "Big Boss" << endl;	//debug
}

Single_Boss::~Single_Boss()
{
    cout<<"Seeyou Boss"<<endl;
}

Single_Boss* Single_Boss::instence()
{
    if(!Boss)
    {
        Boss= new Single_Boss();
    }
    	return Boss;
}

void Single_Boss::run(){
	cout<<"你好,欢迎光临XXX,请问需要点什么服务?"<<endl;
}

int main()
{
	//Single_Boss *boss = new Single_Boss();	//不信的话大可以将这一行放出来,下面那行屏蔽掉试试
    Single_Boss *boss= Single_Boss::instence();	//这是在类外使用单例
    
    boss->run();
    
    return 0;
}

提升部分

多线程下的单例模式

曾经有一份真挚的数据库摆在我眼前,可惜我没有去珍惜它,直到我的项目屡屡崩溃,我才知道,如果能重来,我要加个锁。。。

俱往矣,数风流人物,还看今朝。

来我们重新审视一下下面这段代码:

代码语言:txt
复制
Single_Boss* Single_Boss::instence()	//1
{										
    if(!Boss)							//2
    {									
        Boss= new Single_Boss();		//3
    }									
    return Boss;						
}										

如果在多线程情况下,一旦有两个线程同时进入了 2 ,怎么办?这不是十分正常的事情吗?一点防范都没有,这不是送人头的行为吗?

白给!!

所以,改一下:

代码语言:txt
复制
Single_Boss* Single_Boss::instence()	//1
{					
	lock(db_mutex);	//假设这个锁我已经初始化过了					
    if(!Boss)							//2
    {									
        Boss= new Single_Boss();		//3
    }				
    unlock(db_mutex);	//上锁和解锁一定要同时写,就算忘记写中间步骤,也要先写解锁					
    
    return Boss;						
}	

这样写,可还行?

当然可以。

也可以这样再加上一层,会好一些:

代码语言:txt
复制
Single_Boss* Single_Boss::instence()	//1
{				
	if(!Boss){			//一重锁定
		lock(db_mutex);				
	    if(!Boss)		//二重锁定				
	    {									
	        Boss= new Single_Boss();		
	    }				
	    unlock(db_mutex);	//上锁和解锁一定要同时写,就算忘记写中间步骤,也要先写解锁					
    }
    return Boss;						
}

这个是“懒汉式单例

饿汉式单例

什么是饿汉式呢?饿汉模式的关键:初始化即实例化

微调上面的代码:

代码语言:txt
复制
Single_Boss *Single_Boss::Boss= new Single_Boss();

Single_Boss* Single_Boss::instence()
{
//不需要进行实例化
    //if(!Boss)
    //{
    //    Boss= new Single_Boss();
    //}
   	return Boss;
}

一般饿汉式加载所导致的弊端是可能我并不想使用实例但是实例已经被构造,相对于懒汉式的用则构造会造成内存的浪费,但是其实现方式很简单。

懒汉还是饿汉?

选哪个可以看个人喜好吧,这里给出一点建议:

代码语言:txt
复制
懒汉:在访问量较小时,采用懒汉实现。这是以时间换空间。

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

单例模式的优缺点

优点

代码语言:txt
复制
由于单例模式在内存中只存在一个对象,减少了内存的开支,特别是当对象需要频繁的创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
代码语言:txt
复制
单例模式可以避免对内存的多重占用。
代码语言:txt
复制
单例模式可以在系统设置全局的访问点,优化和共享资源访问。这招我经常用,也很喜欢,因为确实方便,做一个标志位单例类,负责所有数据表的映射处理。(要了解可以私信我)

缺点

代码语言:txt
复制
单例模式一般没有接口,难以拓展。如果要拓展,考虑重构。
代码语言:txt
复制
单例模式对于测试是不利的。在并发环境中,如果单例没有完成,是不能进行测试的。
在这里插入图片描述
在这里插入图片描述

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 单例模式
  • 代码实现
  • 提升部分
    • 多线程下的单例模式
      • 饿汉式单例
        • 懒汉还是饿汉?
          • 单例模式的优缺点
          相关产品与服务
          数据库
          云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档