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

设计模式:单例模式

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.

相关推荐
热点推荐
乱花渐欲迷人眼……

乱花渐欲迷人眼……

印象逍遥子
2025-04-02 23:10:59
抖音回应刘畊宏被强制关播:存在不当着装问题,关播前提示过3次

抖音回应刘畊宏被强制关播:存在不当着装问题,关播前提示过3次

三言科技
2025-04-02 17:42:33
中国有钱人不一定买宝马,但开“以下五款车”的人,家境绝对不差

中国有钱人不一定买宝马,但开“以下五款车”的人,家境绝对不差

鱼汤车趣视界
2025-03-31 09:16:13
中国千万不能武统台湾!一旦对台用武力,将出现三大严重后果

中国千万不能武统台湾!一旦对台用武力,将出现三大严重后果

星辰故事屋
2024-10-20 15:40:12
ESPN第三次MVP模拟投票:亚历山大无悬念第一 詹姆斯位列第六

ESPN第三次MVP模拟投票:亚历山大无悬念第一 詹姆斯位列第六

惊奇侃球
2025-04-03 00:09:41
无滤镜大变样,林志颖像人妖,闫妮黑胖土,辣目洋子丑到认不出

无滤镜大变样,林志颖像人妖,闫妮黑胖土,辣目洋子丑到认不出

林轻吟
2025-03-14 06:35:03
51岁前央视主持人曹颖近照曝光,双眼凹陷无神,脸肿成馒头好奇怪

51岁前央视主持人曹颖近照曝光,双眼凹陷无神,脸肿成馒头好奇怪

嫹笔牂牂
2025-04-02 06:40:05
国乒待遇:陪练发2皮箱衣服,主力想穿多少都有,每天300元伙食费

国乒待遇:陪练发2皮箱衣服,主力想穿多少都有,每天300元伙食费

振华观史
2025-04-02 11:27:12
两失误丢球,泰山05后新星踢不了 难怪老崔不用 刘洋红牌头也不回

两失误丢球,泰山05后新星踢不了 难怪老崔不用 刘洋红牌头也不回

替补席看球
2025-04-02 21:44:42
宁德时代:发生高速爆燃事故的小米 SU7 用的不是我们的电池

宁德时代:发生高速爆燃事故的小米 SU7 用的不是我们的电池

IT之家
2025-04-02 10:53:18
争议!张宁场均16分输7.4分任骏飞无缘第六人奖 山西第二颗粒无收

争议!张宁场均16分输7.4分任骏飞无缘第六人奖 山西第二颗粒无收

醉卧浮生
2025-04-02 20:18:01
烽火通信业绩快报:2024年净利润6.99亿元 同比增加38.38%

烽火通信业绩快报:2024年净利润6.99亿元 同比增加38.38%

每日经济新闻
2025-04-02 16:29:07
未来三年:大大方方小气,认认真真存钱

未来三年:大大方方小气,认认真真存钱

十点读书
2025-04-01 19:12:57
三款iPhone将无缘iOS 19,苹果最大规模更新自2013年以来

三款iPhone将无缘iOS 19,苹果最大规模更新自2013年以来

龙剑秀南
2025-04-01 17:20:39
记者:国安这么使用塞鸟难让他有好状态 工兵型的古加拿球太多

记者:国安这么使用塞鸟难让他有好状态 工兵型的古加拿球太多

直播吧
2025-04-02 21:37:14
51岁金城武终于露面,近照彻底粉碎“男神滤镜”,竟和古天乐撞脸

51岁金城武终于露面,近照彻底粉碎“男神滤镜”,竟和古天乐撞脸

温读史
2025-03-31 17:44:10
重磅!解散"国资委",移动归公安,其他越南运营商归军队和财政!

重磅!解散"国资委",移动归公安,其他越南运营商归军队和财政!

风到腰弯
2025-04-02 09:09:03
离谱!母亲想学烘焙但没钱,把自己27天大的孩子卖了?!只要6000块...

离谱!母亲想学烘焙但没钱,把自己27天大的孩子卖了?!只要6000块...

英国那些事儿
2025-04-01 23:37:26
舒淇大尺度“黄”照,不怕走光……

舒淇大尺度“黄”照,不怕走光……

印象逍遥子
2025-04-02 15:23:36
股市成交额跌破万亿,任由收割股民的结果

股市成交额跌破万亿,任由收割股民的结果

梦马笔谈
2025-04-02 19:58:49
2025-04-03 00:35:00
青石野草
青石野草
岁月不请自来,青春不告而别。
56文章数 75关注度
往期回顾 全部

科技要闻

再跌超4%!小米两天市值缩水超1200亿港元

头条要闻

外媒称缅甸军政府对中国红十字会车队鸣枪 外交部回应

体育要闻

成为最好的球员,更要成为生活中的勇士

娱乐要闻

汪小菲给S亲友发喜帖,对方婉拒不赏脸

财经要闻

"家装第一股"东易日盛资金链断裂真相

汽车要闻

小米SU7爆燃事故 雷军: 会用行动回答大家的问题

态度原创

教育
健康
数码
家居
公开课

教育要闻

高校专项计划,谁可以申报?

嚼槟榔+吸烟+HPV感染=口腔癌?

数码要闻

三星 Galaxy Tab S10 FE 系列平板海外发布,579 欧元起

家居要闻

美式复古 设计大胆独特

公开课

李玫瑾:为什么性格比能力更重要?