重构 - 理解设计模式的捷径(6 附录)

本文通过一个单机策略冒险游戏的实际案例,详细介绍了如何使用单例模式确保程序只开启一个实例,并解决了在MFC单文档视图结构中多次启动程序的问题。通过对比两种不同的实现方式,阐述了正确理解和运用单例模式的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

5 附录 单例模式思想的引入

       本来就可以直接结束了,不过应老师的需求,需要引入至少三种设计模式,所以就把另外一种模式 单例模式放在这里介绍一下吧。为什么要放到最后一章才讲呢?因为虽然用到了这个模式,不过毕竟它和前面介绍的演化过程没有什么关系,所以就拿出来单独介绍了。

       事实上笔者是某一天在看过这个模式后突然想到:作为单机版的策略冒险游戏,不应该支持开多个窗口,否则玩起来数据就全部乱套了。于是联想到自己写的这个不像游戏的“游戏” ,才猛然发现情况不妙:里面并没有引入单例机制,不一定可以控制只开一个窗口。然后拿出来一运行,果然如此:几个“Braver.exe 在任务管理器中排成一列,频频向玩家“招手”

       这可不行!要改过来。于是利用单例模式的思想开始重构了。在MFC的单文档视图结构中,程序的入口点是CWinApp对象,所以将它封装一下应该没有问题了。不到半小时,笔者的第一份代码就出来了:

图 5.1 CWinApp的定义

图 5.2 单例模式的实现(1)

因为只是单机游戏,没有分布式,也没有互联网,所以这个单例模式实现的相当简单。不过它是一个失败品。因为当我连续几次双击“Braver.exe 之后,任务管理器的那一长排“士兵” 又开始向我“敬礼” 了。这也就是为什么上面这张图要命名为“单例模式的实现(1)”的原因了。

笔者在当时是相当困惑的:明明全部都是按照单例模式的实现套路来的,为什么会失败呢?于是在网上请教了高人。答案很简单:问题就出在_instance这个私有变量最初的赋值语句是否生效。之所以会产生多个实例,就是_instance的初始赋值语句“失效”了,换句话说,程序是在产生实例之后才对_instance变量赋值的。单例模式要起作用,就必须让赋值语句在实例产生之前就生效,否则实例化的判断将不起任何作用。这也就是这个方案失效的原因所在了。

那么怎么解决这个问题呢?从高人那里得知,原来MFC的单文档视图程序的单例模式有它自己独特的实现方式,现在笔者就把它贴出来:

图 5.3 单例模式的实现(2)

初看上去,这段代码和单例模式的实现方式八竿子打不着嘛。但是请仔细分析这段代码,尤其是加圈的地方。这段程序的hMutex对象的作用就相当于单例模式的_instance变量,而第一句的作用就是在生成实例之前初始化hMutex。初始化成功之后就是判断,后面的ERROR_ALREADY_EXISTS宏的作用就是指明应用程序的实例已经存在了(因为互斥对象已经存在了),不可以再产生了!然后程序就直接返回,这样就实现了单例模式的效果。所以这段代码的思想实际上还是用的单例模式的思想。那位高人告诫我:不可以机械化地理解设计模式,提炼出模式的思想最重要,要根据场合灵活地运用这些思想来进行设计。真的是一句中的啊!单例模式的思想是什么?概括为一句就是利用特定的“标志”来决定是否生成实例。在经典的单例模式的实现中,对象是否为“NULL 就是“标志” 。而在这段程序中,互斥对象是否已经存在就是“标志” ,互斥对象存在,实例就存在,互斥对象不存在,实例就不存在。所以思想是一致的。这也就是本章的标题起为“单例模式思想的引入”的原因了。

好了,全部的“演化”和“设计”就介绍到这里。如果对本程序源代码感兴趣的,欢迎光临csdn的下载频道(http://yao050421103.download.youkuaiyun.com/),笔者这个程序的最终版本的代码将在这里发布。

附:单例模式的经典定义。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值