你熟悉这段代码吗:
1 | public class X { |
当然。这是GOF这本书里面提到的单例模式。但是我总是听到别人说我们不应该使用它。
为什么我们不应该使用它?
因为它使得我们的系统难以测试
真的吗?为什么会那样呢?
因为你不能模拟(mock)一个单例对象。
不能吗?为什么不能?
这样说吧,因为唯一能够访问私有变量的类只有单例对象自身,不暴露给外部就没办法模拟(mock)。
你知道封装和测试的规则吗?
嗯,不知道。规则是什么呢?
测试胜过封装。
这是什么意思呢?
意思就是测试赢了封装。只是为了维持封装性的话,没有测试会被限制访问某个变量。
你的意思是如果测试需要访问私有变量…
…变量不应该是私有的。对。
听起来好像不对。我的意思是,封装,呃,很重要!
测试更为重要。
等等。什么?
如果代码不能够被测试,封装性好的代码又有什么好的呢?
好,好吧,但是如果我们不得不测试单例对象呢。
看如下代码。
1 | public class X { |
哦,你把实例变量变成“包”范围。
对。
这样的话你就可以模拟单例对象了。
对。考虑一下代码:
1 | public class X { |
等等!实例方法哪去了?
我不需要实例方法。
哦,这个实例变量是公共的。你可以直接使用它。
对。
但是…但是…其他人可能重写它?
谁会做那事?
我不知道。呃,某些坏人吧。
你们团队有这种坏人吗?
没有。但是。只是感觉这样做不太安全。
这样,如果它是公共API的一部分,我同意你的观点。但是如果这段代码只会被我们项目用到那就另当别论了…
我们应该信任我们团队成员?
当然。
这样更容易模拟(mock),对吗?
当然。
如此的话我猜我们应用使用单例模式如果我们想用的话。
当然。经管大多数情况下我不想。
这一番讨论之后,你现在却想告诉我你不想使用单例模式?
是这样,我想理解为什么不适用它更为重要。
好吧,为什么你不适用单例模式?
我有时候也用。特别是在做公共APIs的时候。
你的意思是又是信任的问题?
对。在公共API中如果我想确保只有一个实例被创建时,我就会使用单例模式。
好吧,但是如果不是在做公共API的时候,但是你任然想只创建一个实例呢?
这样的话,我就直接的创建一个。