网易首页 > 网易号 > 正文 申请入驻

设计模式:单例模式

0
分享至

1. 基本概念

1.1 原理

单例模式可以说是所有设计模式中最简单的一个了,这里我们先直接给出它的概念然后再对它进行详细的讲解。单例模式就是:一个类只能有一个实例,并提供对该实例的全局访问点。通俗地说,就是一个类只能创建一个对象,并且在程序的任何地方都能够访问到该对象。

在某些情况下一些类只需要一个实例就够了,我们以一个简化的文件管理器作为例子来说明。假设该文件管理器具备如下功能:

1. 查看一个文件是否存在;

2. 创建一个文件;

3. 删除一个文件。

为了执行这些查看、创建或删除的任务,我们首先肯定要创建该文件管理器类的一个对象,然后在该对象上调用执行相应任务的方法(也叫成员函数)。假设我们可以为该类创建多个对象,那么这些对象的作用都是完全一样的(在同一台设备上执行文件相关操作,即这些对象都操作同一个文件系统)。因此,我们没有必要创建这么多个对象,只要有一个就行了。

此外,在另一些极端情况下某些类只能有一个实例;如果存在多个实例,那么在多个地方对同一组数据进行操作可能导致数据不一致等错误情况。这就是单例模式存在的原因。

因为只需要创建该类的一个实例,不需要频繁地创建和销毁多个实例,因此单例模式可以节省内存并提高性能。不仅如此,它还让程序代码组织得更好,更简单易读。

1.2 结构

图1 单例模式的类图

在文章开篇我们就说了单例模式是最简单的设计模式,因此它的类图也是相当的简单,整个类图中就只有一个类,如图1所示。

这个唯一的类就是要实现为单例模式的类,你可以给它取任意的名字,这里显示为Singleton仅仅是为了表明它是一个单例类而已。为了简单起见,该类图只显示了该类的一个私有静态成员变量、一个公有静态方法(又叫静态成员函数)以及一个私有的构造函数,它们的作用会在后面的实现部分进行说明。

提示,在UML类图中成员前面的减号(-)表示私有(private)、加号(+)表示公有(public)以及井号(#)表示受保护的(protected)。

1.3 实现

既然知道了单例模式的原理,我们就要考虑如何实现它了。根据它的概念,我们要实现单例模式就是要解决两个问题:

1. 该类只能创建一个实例;

2. 该实例全局可访问。

首先为了满足第一个问题,我们必须让该类的构造函数是protected或private修饰的,绝对不能为public。否则,用户可以自行创建该类的多个实例,因为他可以直接访问该类的构造函数。即便我们在文档中指明该类只应该创建一个实例,他们也很可能不会遵守。

当一个类的构造函数为protected或private的时候,它自身是可以访问这些构造函数的,所以我们必须让单例类自己创建自己的实例。因此我们必须为该类提供一个静态方法,因为静态方法可以直接在类上调用、即便此时还不存在该类的实例。从上面的类图中我们可以看到单例类有一个名为getInstance的方法,它就被标记为静态的和公有的。

该静态方法还需要保证它只会创建一个实例,它可以这样做:先检查是否已创建了该单例类的一个实例,如果有就直接返回该实例,如果没有就先创建一个新实例再返回该实例。

再来看第二个问题,初看我们可以提供一个全局变量来保存该单例类的唯一实例。这确实可以提供全局访问点,但是该全局变量可能被用户赋予其它的值,这就造成了程序的混乱。

既然,我们都已经让该单例类自己创建它的实例了,那么为什么也不让它自己负责保存自己的实例呢?我们再为该类提供一个静态成员变量(类图中名为instance),用它来保存该类的唯一实例。注意该静态成员变量必须是private的,以防止用户可以直接访问到它。如果用户想要访问该单例类的唯一实例,它只能调用该类的静态方法(getInstance)。

由此可见,该静态成员变量、静态方法和私有构造函数对实现单例模式至关重要。所以为了简单起见,在图1所示的类图中只显示了这三个成员,但你需要明白该类应该还有其它的非静态的成员变量和方法。当获取到该类的唯一实例后,就在该实例上调用这些其它方法来执行该类提供的功能。

2. 示例

关于单例模式的所有知识都讲解得差不多了,虽然看似文字比较多,但其实很简单。现在,我们就通过实际的代码来演示单例模式。首先,我们用单例模式实现一个名为FileManager的类,它的代码如下所示。

使用该单例类的用户代码如下所示:

对上面的实现方式还有一点需要说明,那就是该实现方式叫做懒汉式。这是因为只有在第一次调用getInstance方法的时候才会创建该单例类的唯一实例,而在这之前程序中都没有该类的实例存在。这种延迟创建的方式的好处是它可以节省内存占用,如果在程序的整个执行期间都不需要访问该单例类的实例,那么在整个程序生命期中都不会创建该实例。

但是,这种懒汉式也有一个缺点,那就是它不是线程安全的。比如有两个线程A和B交替执行,A先执行并且它判断出instance为null。然后切换到线程B,此时它也判断出instance为null,所以它会实例化该单例类并赋值给instance变量。这个时候A线程恢复执行,因为它之前已判断了instance为null,所以它也会实例化该单例类并赋值给instance变量。在我们这个足够简单的例子中看起来这没有多大问题,但在更复杂的真实环境中它可能带来致命的错误。

可以通过线程同步来解决这一问题,比如锁机制;如果使用的是Java语言的话,也可以使用它的synchronized关键字,synchronized关键字的作用和锁机制一样,它自动为一个方法提供线程同步的功能。采用了synchronized关键字的Java代码如下所示:

引入了synchronized关键字后,虽然解决了问题但会导致程序运行变慢。在Java中单例模式还有一种实现方式叫做饿汉式,它在加载该单例类的时候就创建它的唯一实例,那么在getInstance方法中就只需返回该实例即可,无需再判断instance变量是否为null。但是这样的话,即便在整个程序生命周期中都没有使用该单例类,它的实例也被创建了,会占用一部分内存空间。饿汉式的实现代码如下:

(完)

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
超勇士升西部第一!雷霆大胜国王 亚历山大37+11德罗赞30分

超勇士升西部第一!雷霆大胜国王 亚历山大37+11德罗赞30分

醉卧浮生
2024-11-26 13:33:31
网传女子高速一边智驾,一边玩牌!网友提醒被反怼“那是你没有”

网传女子高速一边智驾,一边玩牌!网友提醒被反怼“那是你没有”

火山诗话
2024-11-26 11:54:17
【汽车人】“在中国,为全球”,北京现代回应时代之问

【汽车人】“在中国,为全球”,北京现代回应时代之问

汽车人传媒
2024-11-22 16:52:21
特朗普政府最反华的华裔官员出炉,祖籍广东

特朗普政府最反华的华裔官员出炉,祖籍广东

大国纪录
2024-11-25 22:05:54
认知崩塌!曝国外女子用追踪器调查回收塑料的去向,竟然发现:再利用率为0%!

认知崩塌!曝国外女子用追踪器调查回收塑料的去向,竟然发现:再利用率为0%!

小星球探索
2024-11-25 16:22:06
加拿大有点懵!刚打算“献祭”墨西哥 今日却一同成了特朗普关税目标?

加拿大有点懵!刚打算“献祭”墨西哥 今日却一同成了特朗普关税目标?

财联社
2024-11-26 11:22:18
罕见人生|被忽视的“胎记”:女儿确诊罕见病后,一个父亲发起病友自救

罕见人生|被忽视的“胎记”:女儿确诊罕见病后,一个父亲发起病友自救

澎湃新闻
2024-11-25 16:44:34
形势到底有多严峻?某大学全班22人找不到工作,辅导员崩溃破防…

形势到底有多严峻?某大学全班22人找不到工作,辅导员崩溃破防…

慧翔百科
2024-11-25 20:48:35
没让大陆失望!蔡英文返台,下飞机前讲出3个词,民进党底牌打光

没让大陆失望!蔡英文返台,下飞机前讲出3个词,民进党底牌打光

现代小青青慕慕
2024-11-26 07:20:34
湖北黄冈58岁高三教师在宿舍离世,当地教育局已介入处理

湖北黄冈58岁高三教师在宿舍离世,当地教育局已介入处理

现代快报
2024-11-26 13:38:30
上班后终于理解为什么很多人微信名用真名了,太社死了!

上班后终于理解为什么很多人微信名用真名了,太社死了!

黄丽搞笑小能手
2024-11-25 19:23:30
黄圣依麦琳打架?再见爱人节目组回应:有人冒称前员工,捏造虚假内容,呼吁大家明辨事实理性观看

黄圣依麦琳打架?再见爱人节目组回应:有人冒称前员工,捏造虚假内容,呼吁大家明辨事实理性观看

极目新闻
2024-11-26 14:03:28
尼克斯三巨头93分大胜掘金 威少末节24分创纪录阿奴首次40分

尼克斯三巨头93分大胜掘金 威少末节24分创纪录阿奴首次40分

醉卧浮生
2024-11-26 12:20:52
李晨大腹便便体重162斤,夜宵还吃可乐泡面,沙溢:你都胖了还吃

李晨大腹便便体重162斤,夜宵还吃可乐泡面,沙溢:你都胖了还吃

西瓜爱娱娱
2024-11-26 10:31:00
网友:现在雷克萨斯全系都崩盘,优惠12万,感觉离开中国不远了

网友:现在雷克萨斯全系都崩盘,优惠12万,感觉离开中国不远了

火山诗话
2024-11-26 09:57:32
体育总局体操中心回应吴柳芳被批视频擦边:领导还在研究怎么去处理

体育总局体操中心回应吴柳芳被批视频擦边:领导还在研究怎么去处理

懂球帝
2024-11-25 19:15:18
特朗普宣布将对中国商品额外征收10%关税,中方回应:贸易战和关税战不会有赢家

特朗普宣布将对中国商品额外征收10%关税,中方回应:贸易战和关税战不会有赢家

界面新闻
2024-11-26 11:06:07
抚顺市监局一副处长长期性骚扰已婚女性?当地:被举报人不是干部,市纪委已介入

抚顺市监局一副处长长期性骚扰已婚女性?当地:被举报人不是干部,市纪委已介入

极目新闻
2024-11-26 13:32:34
币圈“孙割”,纵享逃脱人生

币圈“孙割”,纵享逃脱人生

蓝鲸财经
2024-11-26 11:14:46
突发!美媒:以色列和黎真主党达成停火协议!黄金、国际油价大跌

突发!美媒:以色列和黎真主党达成停火协议!黄金、国际油价大跌

每日经济新闻
2024-11-25 23:55:12
2024-11-26 14:32:49
青石野草
青石野草
岁月不请自来,青春不告而别。
56文章数 75关注度
往期回顾 全部

科技要闻

瑞银:跨国汽车公司在华产能冗余达千万辆

头条要闻

女儿洗澡时下体出血确诊患罕见病 家长:无药可医

头条要闻

女儿洗澡时下体出血确诊患罕见病 家长:无药可医

体育要闻

37岁,他用“半条右腿”重返巅峰

娱乐要闻

分手复合又打胎,黄晓明说希望是一场梦

财经要闻

洪灏刘煜辉对谈实录 涉及A股、债务等!

汽车要闻

入华10年 林肯用宋锦将美式豪华“中国化”

态度原创

家居
时尚
本地
手机
游戏

家居要闻

色彩搭配 活跃空间气氛

今冬穿“奶甜风”的女生们,等着被夸吧!

本地新闻

城市24小时|领跑万亿城市,武汉“开挂”了?

手机要闻

关于iPhone 16的散热问题,我们采访了苹果高管

超标!云顶之弈三张新六费卡被曝,网友:这概率能拿到?

无障碍浏览 进入关怀版