模式批判之Singleton

本文探讨了Singleton模式的优缺点,指出其常见的误用场景,并提供了正确的使用建议。文章强调了不当使用Singleton可能导致的问题,如代码耦合度增加等。

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

               人们常说,模式是解决方案的重用,是经验的重用。借助已有的经验和典范,可以帮助我们少走弯路,还可以在更高的语言层次描述系统和相互沟通。然而,模式本身是如此的抽象,对于模式的理解和运用很大程度上依赖于程序员个人或团队的经验和技艺。模式是很好的东西,然而传授模式却是如此的困难。模式的适用性是一个非常重要的指标,错误地运用模式,将会加剧表达的不自然,恶化代码的可读性和可维护性。然而,模式的误用还相当广泛,Singleton就是非常典型的例子。

说到Singleton,就不能不提全局变量。过去我们反对全局变量,为什么呢?全局变量一般存在三个问题:

1.      命名冲突,也叫名字污染

2.      初始化顺序依赖问题。

3.      远程代码耦合问题。

对于第一个问题,其实解决很简单,通过命名规范可以有效解决。另外,借助语言机制也容易解决,例如C++namespace, classstruct的静态数据成员。JavaC#根本不允许全局变量,并且引入包机制,都可以缓解甚至消除这一影响,至少,Singleton对该问题的解决力度并不超过这些语言提供的内建机制。

初始化顺序依赖问题是一个相当微妙的问题。借助于Singleton, 我们可以强制某些对象按需创建,避免初始化顺序依赖导致的问题。然而,初始化顺序是一个雷区,我们必须小心翼翼地绕过去,但首先不应该通过实现技术来规避问题,而应该调整设计,让初始化顺序问题根本不出现才是上策。第二,某些情况下,我们确实需要规避初始化顺序问题,我们也需要清醒地认识到该实现手段影响到的代码范围,受其影响的部分越单一越好。

远程代码耦合,这是我们反对全局变量的核心问题。任何长距离的耦合都将导致代码的可读性下降,进而可能影响代码结构,导致结构僵化,无力应对因需求变化导致的结构调整。很遗憾,Singleton并不能对这个问题有任何帮助。当我们回避全局变量的时候,事实上,我们也规避了上述的三个问题。可是,如果我们不能审慎地使用Singleton就会重新落入全局变量的核心陷阱中去。

然而,Singleton确实是运用的最为广泛的模式之一,我的第一个模式的尝试也是从Singleton开始的。这只能归功于这一模式概念上的简单性和实现上的方便性:一个变形的全局变量类静态变量,函数局部静态变量--就可以成为该模式的实现。再加上模式传授的困难性,简单性和误解,导致了该模式的滥用。

事实上,对于许多程序员来说,都不能熟练运用设计模式。往往是一些资深的程序员会首先尝试使用,然而,即便是资深的程序员,对模式的运用常常也是不正确的。由于资深程序员的权威性,导致了这些错误的模式运用得以进一步扩散。

除了前述的3个问题外,在该模式的实现上也存在许多问题。典型的例子包括:类静态成员实现,该实现导致并不能解决问题2。动态创建,却没有实现释放对象的机制。对于多线程环境,没有考虑安全性问题。当然,并非所有环境都需要解决这些问题,但是这些问题应该是被考虑过的。

什么是Singleton适用的时候?没有确定的答案。从我的经验来说,有一些方法,可以帮助我们。例如,尽量避免函数有状态,宁可要函数状态和对象有关而不要和全局对象有关。无状态的函数是好的,而不恰当的Singleton则会导致某些函数有状态。

我会采用Singleton的一般是和静态类型信息关联的地方,例如,需要向某个注册表中注册许多类的创建器,这个注册表可以实现为Singleton,然后把注册过程利用局部静态对象的构造函数来自动实现。这个注册过程是个单一的过程。另外,Singleton作用于静态信息,需要变化的风险大大降低。不过,我似乎还从未依靠静态变量解决过初始化依赖顺序问题。但是,初始化依赖顺序不是一定可以回避的,这时候使用Singleton也是合理的。

而通常Singleton的误用则有:用于程序运行的环境变量,资源管理器,特殊的资源,会话,数据库连接等等。这些内容没有必要设计成Singleton,如果程序扩展,你可以应付多会话,多数据库连接等等问题。一旦使用了Singleton,所有这些扩展都将成为噩梦。现实是,一个有价值的程序,总是会被要求应付更复杂的环境。

 <iframe frameborder="0" id="gn_notemagic" style="position: absolute; display: block; opacity: 0.7; z-index: 500; width: 18px; height: 22px; top: 152px; right: 160px;" src="http://www.google.com/gn/static_files/blank.html"></iframe>
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值