至于大写-S“Singleton”是否合适……问问自己这个……
第二次实例肯定会导致我的程序死亡吗?
(我的意思是“确定”和“死亡”。不仅仅是“可能”......而且不仅仅是关于哪个实例是“官方”实例的一些混淆。如果程序崩溃,内爆,打开虫洞,放火你的狗等完全由于第二个实例的存在,答案是“是”。如果你不确定,假设“否”,直到你有充分的证据。)
如果答案是“是”,那么您可能有使用 Singleton 的有效案例。如果不是,那么您就是在滥用它,并且有一个更好的解决方案:
只是不要创建第二个实例。
使用 Singleton 有几个错误的原因:
“我希望能够使用我的对象,而无需在应用程序中传递它。” 你猜怎么了?你所拥有的是一个美化的全局变量。当它藏在某个阶级的内心深处时,它甚至比它坐在外面让全世界都看到更邪恶。 如果你想使用一个全局,那么使用一个该死的全局。 不要将它隐藏在吸气剂后面,并认为人们不会注意到。
“我只需要其中一个。” 往上看。 你只需要一个?只创建一个。 不管你现在是否需要它,你有充分的理由强迫它永远存在吗?如果你将来想要另一个怎么办?您不仅让创建另一个类变得很痛苦,而且您可能已经以一种只能存在一个的方式构建您的类——并且将有很多“设计”要撤消。
“能说出来很方便MySingleton.getInstance()
。” 是的,直到你开始关心测试。看,每次调用 时MySingleton.getInstance()
,您都添加了一个假设,即这是该对象可以是唯一的类型。如果你开始搞乱单元测试,你的测试将毫无用处,因为它们都依赖于那个实例的行为——甚至是测试运行的顺序。即使是全球性的可测试性也没有那么糟糕,而且有点糟糕。(另外,请参阅上面的“......没有在应用程序周围传递它”。)
单例问题的解决方案一般是依赖注入。大话,但前提非常非常简单;非框架版本基本上是,“对象需要完成其工作的外部东西?将它传递给构造函数。” 据说有 DI 容器库/包可以简化这一点,但这一切都只是告诉对象使用什么,而不是让它自己去寻找东西。所以你将你的一个实例传递给需要它的对象,它永远不必说MySingleton.
什么——甚至不关心那个对象是否是单例。