什么是替代单身

我们有一个保存应用程序configuration信息的类。 它曾经是一个单身人士。 经过一些build筑审查,我们被告知要删除单身人士。 我们确实看到了在unit testing中不使用单例的一些好处,因为我们可以一次testing不同的configuration。

如果没有单例,我们必须在代码中的任何地方传递实例。 它变得如此混乱,所以我们写了一个单例包装器。 现在我们将相同的代码移植到PHP和.NET,我想知道是否有更好的模式,我们可以使用configuration对象。

Googletesting博客有一系列关于避免Singleton(为了创build可testing的代码)的条目。 也许这可以帮助你:

  • 使用dependency injection来避免单例
  • 单身人士是病理性的说谎者
  • 单身人士的根本原因
  • 所有的单身人士都去了哪里?

最后一篇文章详细解释了如何将新对象的创build移动到工厂中,这样就可以避免使用单例。 值得肯定的阅读。

简而言之,我们将所有新的操作员移到一个工厂。 我们将所有类似生命周期的物体分成一个工厂。

最好的方法是使用工厂模式。 当你构造一个新的类的实例(在工厂中)时,你可以将“全局”数据插入到新构造的对象中,或者作为单个实例的引用(存储在工厂类中),或者通过复制相关数据导入新的对象。

然后你的所有对象将包含曾经居住在单身人士的数据。 我不认为总体上有很大差异,但它可以使你的代码更容易阅读。

我可能会在这里说明一些明显的问题,但是为什么不能使用像Spring或Guice这样的dependency injection框架呢? (我相信Spring现在也可以用于.NET)。

这样一来,框架就可以拥有一个configuration对象的副本,而你的bean(服务,DAO等等)不必担心查找它。

这是我通常采取的方法!

如果你使用Spring Framework ,你可以创build一个普通的bean。 默认情况下(或者如果你明确地设置scope="singleton" ),只创buildbean的一个实例,并且每当bean在依赖中被使用或者通过getBean()获取时,这个实例被返回。

你得到了单一实例的优点,没有Singleton模式的耦合。

另一种方法是传递你需要的东西,而不是要求一个对象的东西。

不要将责任积累到一个configuration对象上,因为它会以一个非常难以理解和脆弱的大对象结束。

例如,如果您需要另一个参数到特定的类,则更改Configuration对象,然后重新编译所有使用它的类。 这有些问题。

尝试重构您的代码,以避免一个常见的,全局的和大的Configuration对象。 仅将必需的parameter passing给客户端类:

 class Server { int port; Server(Configuration config) { this.port = config.getServerPort(); } } 

应该被重构为:

  class Server { public Server(int port) { this.port = port; } } 

dependency injection框架在这里会有很大的帮助,但并不是非常必要的。

是只包含静态方法和字段的类吗? 我不确定你的情况到底是什么,但是可能值得研究。

取决于正在使用的工具/框架等。 使用dependency injection/ ioc工具,人们仍然可以通过di / ioc容器使用单例行为来获得单例性能/优化(例如IConfigSettings接口),只需创build一个类的实例即可。 这仍然可以取代testing

或者,可以使用工厂来创build类,并在每次请求时返回相同的实例 – 但要进行testing,可以返回一个存根/模拟版本

审查configuration为callback接口的可能性。 所以你的configuration敏感的代码将看起来:

 MyReuseCode.Configure(IConfiguration) 

系统初始化代码如下:

 Library.init(MyIConfigurationImpl) 

您可以使用dependency injection框架来缓解传入configuration对象的痛苦。 一个体面的是ninject ,它有使用代码而不是xml的优势。

您可以使用静态方法完成单例的相同行为。 Steve Yegge在这篇文章中解释得非常好。

也许不是很干净,但你也许可以将你想要改变的信息传递给创build单例的方法 – 而不是使用

 public static Singleton getInstance() { if(singleton != null) createSingleton(); return singleton; } } 

你可以直接在应用程序启动时(以及在unit testing的setUp-Methods中createSingleton(Information info)调用createSingleton(Information info) )。

单身不是邪恶的,但devise模式是有缺陷的。 我有一个类,我只想在运行时创build它的单个实例,但要在unit testing期间创build多个孤立的实例,以确保确定性的结果。

使用Spring等DI,是一个非常好的select,但不是唯一的select。