什么是 Singleton 的替代品

我们有一个类,它保存应用程序的配置信息。以前是单人模式。在一些架构审查之后,我们被告知移除单例模式。我们确实看到了在单元测试中不使用单例的一些好处,因为我们可以同时测试不同的配置。

Without singleton, we have to pass the instance around everywhere in our code. It's getting so messy so we wrote a singleton wrapper. Now we are porting the same code to PHP and .NET, I am wondering if there is a better pattern we can use for the configuration object.

49282 次浏览

只包含静态方法和字段的类是否可能?我不确定你到底是什么情况但也许值得调查一下。

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

然后,所有对象都将包含曾经存在于单例模式中的数据。我不认为总体上有很大的不同,但它可以使您的代码更容易阅读。

我在这里可能是在陈述一个显而易见的事实,但是为什么不能使用诸如 春天吉斯这样的依赖注入框架呢?(我相信春天也可以。NET).

这样,框架可以保存配置对象的单个副本,而且您的 bean (服务、 DAO 等)不必担心查找它。

这是我通常采取的方法!

Maybe not very clean either, but you could maybe pass the information bits you want to have changed to the method that creates the singleton -- instead of using

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

您可以在应用程序启动时直接调用 createSingleton(Information info)(在单元测试的 setUp-Method 中)。

如果使用 Spring 框架,只需创建一个常规 bean。默认情况下(或者如果显式设置 scope="singleton") ,只创建 bean 的一个实例,并且每次在依赖项中使用 bean 或通过 getBean()检索该实例时,都会返回该实例。

你得到了单个实例的优势,没有了单例模式的耦合。

谷歌测试博客有一系列关于避免 Singleton 的条目(为了创建可测试代码)。也许这个能帮到你:

The last article explains in detail how to move the creation of new objects into a factory, so you can avoid using singletons. Worth reading for sure.

简而言之,我们把所有的新经营者都转移到一家工厂。 我们将生命周期相似的所有对象分组到一个工厂中。

Depends on what tooling/frameworks etc.. are being used. With dependency injection/ioc tools one can often still get singleton performance/optimizations by having the di/ioc container use singleton behaviour for the class required - (such as a IConfigSettings interface) by only ever creating one instance of the class. This could be still substituted out for testing

Alternately one could use a factory to create the class and return the same instance each time you request it - but for testing it could return a stubbed/mocked version

另一种方法是传递您需要的内容,而不是请求对象提供内容。

检查将配置作为回调接口的可能性。 So your configuration sensitive code will look:

MyReuseCode.Configure(IConfiguration)

System-init 代码将看起来:

Library.init(MyIConfigurationImpl)

不要将责任累积到单个配置对象 ,因为它将以一个非常大的对象结束,这个对象既难以理解又很脆弱。

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

尝试重构你的代码,以避免一个通用的、全局的和大的 Configuration对象。只向客户端类传递必需的参数:

class Server {


int port;


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


}

应重构为:

 class Server {


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

a 依赖注入架构 will help a lot here, but it isn't stricly required.

您可以使用依赖注入框架来减轻传入配置对象的痛苦。一个不错的例子是 注射,它具有使用代码而不是 xml 的优势。

您可以通过使用静态方法来实现单例的相同行为。Steve Yegge 在 这个文章中很好地解释了这一点。