以下答案是错误的,但我会将其保留,以供其他人学习(请参阅下文)
在中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中),但是我仍然会浪费时间。