单例模式是一种模式,就像其他工具一样,它可以被使用或滥用。
单例的不良之处通常在于用户(或者应该说是在不适当地使用单例来处理其未设计用途的问题上)。最大的问题在于将单例用作虚假全局变量。
void some_class::some_function(parameters, service_provider& srv)
{
srv.get<error_logger>().log("Hi there!");
this->another_function(some_other_parameters, srv);
}
关于这个主题的最新文章是Chris Reath在Coding Without Comments上发表的。
注意:Coding Without Comments已经无效。然而,被链接的文章已被另一个用户克隆。
太多人将不支持线程安全的对象放到单例模式中。我见过一些关于DataContext(LINQ to SQL)的例子,它是以单例模式实现的,尽管DataContext不支持线程安全,而且纯粹只是一个工作单元对象。
关于单例模式,还有一件事情是没有人提到的。
在大多数情况下,“单例性”是某个类实现细节,而不是其接口特征。控制反转容器可以将此特征隐藏在类用户之外;您只需要将类标记为单例(例如,在Java中使用@Singleton
注释),然后IoCC将完成其余工作。您不需要提供对单例实例的全局访问,因为访问已由IoCC管理。因此,IoC单例并没有什么问题。
与IoC单例相反,GoF单例通过getInstance()方法在接口中暴露“单例性”,因此它们受到了上述所有问题的影响。
如果您使用单例模式适当且最小化,那么它并不是邪恶的。有很多其他好的设计模式可以在某些时候替代单例模式(并且也能得到最佳结果)。但是一些程序员不知道这些好的模式,并将单例模式用于所有情况,这使得对他们来说单例模式变得邪恶。
Singleton.getInstance()
对于小而简单的系统可能还可以,但是当需要相同类的不同实例时,它无法运行/扩展。