Posted on 2008-02-23 15:34
dennis 阅读(2113)
评论(5) 编辑 收藏 所属分类:
模式与架构
自从知道singleton模式这把锤子是什么样的之后,我就把很多小疙瘩也当成了钉子,时常想象偶顶着模式的光环挥舞着“万能”锤子在代码丛林中学习兰博搏斗的光辉形象~~~~。昨天读《重构与模式》的inline singleton一节,一句话点醒梦中人,singleton模式是“保证一个类仅有一个实例,并提供一个访问它的全局访问点”,原来——singleton也是全局变量啊。马教主深刻地教育过我们:全局变量在被证明无害之前都是有害。偶大汗淋漓。看看迷恋singleton的几种现象:
1、仅仅在一个地方调用到了某个singleton实例,并且对这个实例的处理代码也集中在这么一两个地方,这样的情况下你为什么要singleton?这里需要一个个全局访问点吗?我看你是为了singleton而singleton。
2、我为了性能优化啊!singleton只有一个实例,减小了创建开销。oh,我终于找到一个用singleton的充分理由了——性能。慢着,跟我读高大师的名言:“不成熟的优化是万恶之源”。你怎么知道singleton对象的重复创建是明显影响了性能?现代jvm对“短命”对象的创建代价已经非常低了。不成熟的优化不仅可能是无效的,而且也给以后重构工作带来了困难。除非有明显数据证明(分析工具而来)某个对象的重复创建是对性能影响极大,否则所谓性能优化不能成为采用singleton模式的理由。
3、有时候我们需要在系统的不同层次间传递一些共享信息,如果不采用singleton对象来提供这些共享信息,就得在调用的方法中重复地传递这些参数,这是个应用singleton模式的场景。但是,如果这些共享信息是可被修改的,或者说singleton对象不是无状态的,如果还采用singleton模式,那么你就不得不在调用的方法中从single对象取出旧信息和存入新信息,这样的重复代码将遍布的到处都是,不仅仅引入了同步访问的需要,而且出错的风险大大提高。这种情况下你还将这些信息作为方法参数传递而不是采用singleton可能更为清晰和健壮。
singleton不仅仅是“保证一个类仅有一个实例”(这仅仅是描述),更重要的是它是用来“提供全局访问点”的(这才是它的功能),不要再迷恋这把锤子,好好利用这把锤子。
题外话:脚本语言似乎更容易滥用全局变量,javascript里可以模拟命名空间,Ruby也可以模拟类似的机制。最近写的一个比较大一点的Ruby脚本,用了几个全局变量(都是数组)用于保存状态数据,一开始没有意识到这一点,导致对全局变量的访问散落在好几个脚本文件里,RDT下看起来红通通的一片极其不爽。那么就重构吧——封装数组重构,将对这些全局数组的访问和修改操作统一到一个模块,调用全局变量的地方都引用这个模块,通过模块去操作全局变量,代码看起来清爽多了。