在什么情况下我应该使用Singleton类?

时间:2008-12-19 22:39:55

标签: c# .net design-patterns oop

this question的完全重复方式关闭。但重新打开,因为其他Singleton问题是一般用途而不是用于DB访问

我在考虑将内部数据访问类设置为Singleton但是无法说服自己选择主要是因为除了方法中的局部变量之外,类没有状态。

毕竟设计这些类作为单身人士的目的是什么? 是否保证顺序访问数据库是不可信的,因为大多数现代数据库都可以很好地处理并发性? 是否能够重复使用单个连接,可以通过连接池来处理? 或者通过运行单个实例来节省内存?

请赐教这个。

11 个答案:

答案 0 :(得分:4)

您可能不希望在您描述的情况下使用Singleton。通过DBD / DBI类型的单个实例与数据库建立所有连接会严重限制请求吞吐量性能。

HTH

欢呼声,

罗布

答案 1 :(得分:3)

在我想之前,我们已经提出了这个问题。看看here

看到这个问题:
On Design Patterns: When to use the Singleton?

答案 2 :(得分:3)

我发现单例模式适用于以下类:

  • 没有州
  • 充满了基本的“服务会员”
  • 必须严格控制其资源。

这方面的一个例子是数据访问类。

你会有接受参数的方法,并返回说,一个DataReader,但是你没有操纵单例中读者的状态,你只需要它,然后返回它。

同时,您可以采用可以在项目中传播的逻辑(用于数据访问),并将其集成到一个管理其资源(数据库连接)的单个类中,无论谁调用它。

所有这一切,Singleton是在完全静态类的.NET概念之前发明的,所以如果你应该采取一种方式或另一种方式,我就会陷入困境。事实上,这是一个很好的问题。

答案 3 :(得分:3)

来自“Design Patterns: Elements Of Reusable Object-Oriented Software”:

  

对某些课程来说很重要   啊,只有一个例子。虽然   一个人可以有很多打印机   系统,应该只有一个   打印机假脱机程序。应该只有   一个文件系统和一个窗口   经理。 ...

     

在以下情况下使用Singleton模式:

     
      
  • 必须只有一个类的实例,并且客户必须可以从众所周知的访问点访问它
  •   
  • 唯一的实例应该可以通过子类化进行扩展,客户端应该能够使用扩展实例而无需修改代码
  •   

一般来说,在Web开发中,实际上应该实现Singleton模式的唯一事情是在Web框架本身;您在应用程序中编写的所有代码(一般来说)都应该采用并发性,并依赖于数据库或会话状态等实现全局(跨用户)行为。

答案 4 :(得分:1)

Singleton是一个有用的设计模式,只允许一个类的实例。 Singleton的目的是控制对象创建,将数量限制为1,但允许在情况发生变化时灵活地创建更多对象。由于只有一个Singleton实例,因此Singleton的任何实例字段每个类只出现一次,就像静态字段一样。

来源:java.sun.com

答案 5 :(得分:1)

  1. 在这里使用单身并不能真正给你任何东西,只有limits flexibility
  2. 你想要并发或者你不会扩展
  3. 担心这里的连接和内存是premature optimization

答案 6 :(得分:1)

近年来,Singleton模式已经失去了很多光彩,主要是由于单元测试的兴起。

单身人士可以使单元测试非常困难 - 如果你只能创建一个实例,那么如何编写需要测试对象的“新鲜”实例的测试?如果一个测试以某种方式修改了该单例,那么针对同一个对象的任何进一步测试都不会真正以一个干净的平板开始。

单身人士也存在问题,因为他们是有效的全球变量。几个星期前我们在办公室遇到了一个线程问题,因为Singleton global正在从各种线程进行修改;开发人员被使用受制裁的“模式”所蒙蔽,没有意识到他真正创造的是一个全局变量。

另一个问题是在某些情况下创造真正的单身人士在病理上是困难的。例如,在Java中,如果没有为Serializable类正确实现readResolve()方法,则可以创建“单例”的多个实例。

不要创建Singleton,而应考虑提供一个返回实例的静态工厂方法;这至少使您能够在不破坏API的情况下改变主意。

Josh Bloch在Effective Java中对此进行了很好的讨论。

答案 7 :(得分:1)

您有一个您想要创建一次的存储库图层,并且该引用在其他地方使用。

如果你使用标准单身,会产生不良副作用。你基本上杀了可测性。所有代码都紧密耦合到单例实例。现在你无法在没有命中数据库的情况下测试任何代码(这使单元测试变得非常复杂)。

我的建议:

  1. 找到您喜欢的IOC并将其集成到您的应用程序中(StructureMap,Unity,Spring.Net,Castle Windsor,Autofac,Ninject ......选择一个)。
  2. 为您的存储库实现一个接口。
  3. 告诉IOC将存储库视为单例,并在代码通过接口请求存储库时返回它。
  4. 了解依赖注入。
  5. 对于一个简单的问题,这是一项很多工作。但你会好起来的。

答案 8 :(得分:1)

作为一个例子,对象工厂通常是单身人士的好选择。

答案 9 :(得分:1)

如果一个类有 no 状态,那么将它作为一个单例是没有意义的;所有表现良好的语言最多只能创建一个指向向量表(或等效结构)的单个指针,用于调度方法。

如果实例状态可能因类的实例而异,那么单例模式将不起作用;你需要不止一个实例。

然后,通过用尽,唯一应该使用Singleton的情况是,必须在所有访问者之间共享状态,并且只有必须在所有访问者之间共享的状态。

有几件事可以导致类似单身人士的事情:

  • 工厂模式:你构建 并使用一些返回一个对象 共享国家。
  • 资源池:您有共享资源 一些有限的资源表, 像数据库连接,你 必须管理一大群人 用户。 (凸起版本在哪里 有一个数据库连接 单身人士。)
  • 外部的并发控制 资源;通常是一个信号量 将成为单身人士的变种, 因为P / V操作必须 自动修改共享计数器。

答案 10 :(得分:0)

用c#,我会说单身人士很少适合。使用静态类可以更好地解决单例的大多数用法。注意线程安全是非常重要的,尽管有任何静态。对于数据库访问,您可能不希望单个连接,如上所述。您最好的办法是创建一个连接,并使用内置池。如果愿意,您可以创建一个返回新连接的静态方法来减少代码。但是,ORM模式/框架可能会更好。

在c#3.5中,扩展方法可能比静态类更合适。