您的位置:首页 > 其它

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

2009-11-21 02:37 316 查看
 

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

       本来就可以直接结束了,不过应老师的需求,需要引入至少三种设计模式,所以就把另外一种模式 – 单例模式放在这里介绍一下吧。为什么要放到最后一章才讲呢?因为虽然用到了这个模式,不过毕竟它和前面介绍的演化过程没有什么关系,所以就拿出来单独介绍了。
       事实上笔者是某一天在看过这个模式后突然想到:作为单机版的策略冒险游戏,不应该支持开多个窗口,否则玩起来数据就全部乱套了。于是联想到自己写的这个不像游戏的“游戏” ,才猛然发现情况不妙:里面并没有引入单例机制,不一定可以控制只开一个窗口。然后拿出来一运行,果然如此:几个“Braver.exe” 在任务管理器中排成一列,频频向玩家“招手” 。
       这可不行!要改过来。于是利用单例模式的思想开始重构了。在MFC的单文档视图结构中,程序的入口点是CWinApp对象,所以将它封装一下应该没有问题了。不到半小时,笔者的第一份代码就出来了:





因为只是单机游戏,没有分布式,也没有互联网,所以这个单例模式实现的相当简单。不过它是一个失败品。因为当我连续几次双击“Braver.exe” 之后,任务管理器的那一长排“士兵” 又开始向我“敬礼” 了。这也就是为什么上面这张图要命名为“单例模式的实现(1)”的原因了。
笔者在当时是相当困惑的:明明全部都是按照单例模式的实现套路来的,为什么会失败呢?于是在网上请教了高人。答案很简单:问题就出在_instance这个私有变量最初的赋值语句是否生效。之所以会产生多个实例,就是_instance的初始赋值语句“失效”了,换句话说,程序是在产生实例之后才对_instance变量赋值的。单例模式要起作用,就必须让赋值语句在实例产生之前就生效,否则实例化的判断将不起任何作用。这也就是这个方案失效的原因所在了。
那么怎么解决这个问题呢?从高人那里得知,原来MFC的单文档视图程序的单例模式有它自己独特的实现方式,现在笔者就把它贴出来:



初看上去,这段代码和单例模式的实现方式八竿子打不着嘛。但是请仔细分析这段代码,尤其是加圈的地方。这段程序的hMutex对象的作用就相当于单例模式的_instance变量,而第一句的作用就是在生成实例之前初始化hMutex。初始化成功之后就是判断,后面的ERROR_ALREADY_EXISTS宏的作用就是指明应用程序的实例已经存在了(因为互斥对象已经存在了),不可以再产生了!然后程序就直接返回,这样就实现了单例模式的效果。所以这段代码的思想实际上还是用的单例模式的思想。那位高人告诫我:不可以机械化地理解设计模式,提炼出模式的思想最重要,要根据场合灵活地运用这些思想来进行设计。真的是一句中的啊!单例模式的思想是什么?概括为一句就是利用特定的“标志”来决定是否生成实例。在经典的单例模式的实现中,对象是否为“NULL” 就是“标志” 。而在这段程序中,互斥对象是否已经存在就是“标志” ,互斥对象存在,实例就存在,互斥对象不存在,实例就不存在。所以思想是一致的。这也就是本章的标题起为“单例模式思想的引入”的原因了。
好了,全部的“演化”和“设计”就介绍到这里。如果对本程序源代码感兴趣的,欢迎光临csdn的下载频道(http://yao050421103.download.csdn.net/),笔者这个程序的最终版本的代码将在这里发布。
附:单例模式的经典定义。
        Singleton:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息