以下答案是错误的,但我会将其保留,以供其他人学习(请参阅下文)
在中ExampleA
,您可以Config
在多个类中使用同一实例。但是,如果Config
整个应用程序中只有一个实例,请考虑应用Singleton模式Config
以避免避免多个实例Config
。如果Config
是Singleton,则可以执行以下操作:
class ExampleA
{
private $config;
public function __construct()
{
$this->config = Config->getInstance();
}
}
$exampleA = new ExampleA();
在ExampleB
,在另一方面,你永远得到一个单独的实例Config
为每个实例ExampleB
。
您应该应用哪个版本实际上取决于应用程序如何处理以下实例Config
:
- 如果每个实例
ExampleX
都应有一个单独的实例Config
,请配合ExampleB
;
- 如果每个实例
ExampleX
将共享一个(并且只有一个)实例Config
,请使用ExampleA with Config Singleton
;
- 如果的实例
ExampleX
可能使用的不同实例Config
,请坚持使用ExampleA
。
为什么转换Config
为单例是错误的:
我必须承认,我昨天才了解到Singleton模式(阅读Head First设计模式书)。我天真地将它应用于本示例,但正如许多人指出的,一种方式是另一种方式(有些方式比较隐秘,只说“您做错了!”),这不是一个好主意。因此,为防止其他人犯与我刚才相同的错误,以下总结了Singleton模式为何有害的原因(基于评论和我发现的谷歌搜索结果):
如果ExampleA
检索到自己对Config
实例的引用,则这些类将紧密耦合。没有办法让实例ExampleA
使用其他版本的Config
(例如某些子类)。如果您想ExampleA
使用的模拟实例进行测试,这将很可怕,Config
因为无法将其提供给ExampleA
。
那里的前提将是一个,只有一个,实例Config
也许认为现在,但你不能总是肯定的是,同样的将持有的未来。如果在以后的某个时刻发现需要多个实例Config
,则没有办法无需重写代码就无法实现。
即使一个Config
永恒的实例对于所有永恒都是正确的,但您可能仍然希望能够使用的某个子类Config
(而仍然只有一个实例)。但是,由于代码是通过方法直接获取实例getInstance()
的Config
,因此static
无法获取子类。同样,必须重写代码。
至少在仅查看的API时,ExampleA
使用的事实Config
将被隐藏ExampleA
。这可能不是一件坏事,但就我个人而言,这感觉像是一种缺点。例如,在进行维护时,没有简单的方法来找出哪些类将受到更改的影响,而Config
无需研究其他所有类的实现。
即使ExampleA
使用Singleton Config
本身并不是问题,但从测试的角度来看,它仍然可能成为问题。单例对象将带有状态,该状态将一直持续到应用程序终止。当您运行单元测试时,这可能是一个问题,因为您希望将一个测试与另一个测试隔离开(即执行一个测试不会影响另一个测试的结果)。要解决此问题,必须在每次测试运行之间销毁Singleton对象(可能必须重新启动整个应用程序),这可能很耗时(更不用说乏味和烦人了)。
话虽如此,我很高兴自己在这里而不是在实际应用程序的实现中犯了这个错误。实际上,我实际上是在考虑重写我的最新代码,以对某些类使用Singleton模式。尽管我可以轻松地还原更改(所有内容都存储在SVN中),但是我仍然会浪费时间。