dyn*_*mic 90 php oop frameworks design-patterns
我们都知道单身人士有多糟糕,因为他们隐藏了依赖关系和其他原因.
但是在一个框架中,可能有许多对象只需要实例化一次并从任何地方调用(logger,db等).
为了解决这个问题,我被告知使用一个所谓的"对象管理器"(或像symfony这样的服务容器),它在内部存储对服务的每个引用(记录器等).
但为什么服务提供商不像纯粹的单身人士那样糟糕?
服务提供商也隐藏了依赖关系,他们只是创建了第一个istance.所以我真的很难理解为什么我们应该使用服务提供商而不是单身人士.
PS.我知道不要隐藏依赖关系我应该使用DI(如Misko所述)
我想补充一点:这些天单身人士不是那么邪恶,PHPUnit的创建者在这里解释:
DI + Singleton解决了这个问题:
<?php
class Client {
public function doSomething(Singleton $singleton = NULL){
if ($singleton === NULL) {
$singleton = Singleton::getInstance();
}
// ...
}
}
?>
Run Code Online (Sandbox Code Playgroud)
这很聪明,即使这根本不能解决所有问题.
除DI和Service Container之外是否有任何可接受的解决方案来访问此帮助程序对象?
Gor*_*don 75
服务定位器只是两个邪恶中较小的一个."较小的"沸腾到这四个差异(至少我现在不能想到任何其他的):
服务容器不像Singleton那样违反单一责任原则.单身人士混合对象创建和业务逻辑,而服务容器则严格负责管理应用程序的对象生命周期.在这方面,服务容器更好.
由于静态方法调用,单例通常被硬编码到您的应用程序中,这导致代码中的紧耦合和难以模拟的依赖项.另一方面,SL只是一个类,可以注入.因此,虽然你所有的分类都依赖于它,但至少它是一个松散耦合的依赖.因此,除非您将ServiceLocator实现为Singleton本身,否则它会更好,也更容易测试.
但是,使用ServiceLocator的所有类现在都依赖于ServiceLocator,这也是一种耦合形式.这可以通过使用ServiceLocator的接口来减轻,因此您不必绑定到具体的ServiceLocator实现,但是您的类将依赖于某种Locator的存在,而根本不使用ServiceLocator会显着地重用.
尽管如此,存在很多隐藏依赖关系的问题.当您将定位器注入到消费类时,您将不会知道任何依赖项.但与Singleton相比,SL通常会实例化幕后所需的所有依赖项.所以当你获取一个服务时,你不会在CreditCard示例中像Misko Hevery那样结束,例如,你不必手动实例化依赖关系的所有依赖关系.
从实例内部获取依赖项也违反了Demeter法则,该法规定您不应该深入研究协作者.一个实例应该只与其直接的合作者交谈.这是Singleton和ServiceLocator的问题.
全局状态的问题也有所缓解,因为当您在测试之间实例化一个新的服务定位器时,所有先前创建的实例也会被删除(除非您犯了错误并将其保存在SL中的静态属性中).当然,对于由SL管理的类中的任何全局状态而言,这都不适用.
另请参阅Fowler on Service Locator vs Dependency Injection以进行更深入的讨论.
关于您的更新的说明以及Sebastian Bergmann关于测试使用Singletons的代码的链接文章:塞巴斯蒂安确实没有提出建议的解决方法使得使用Singleons不是问题.这只是制作代码的一种方法,否则将无法测试更可测试的代码.但它仍然是有问题的代码.事实上,他明确指出:"只因为你可以,并不意味着你应该".
jas*_*son 42
服务定位器模式是反模式.它没有解决暴露依赖关系的问题(你不能通过查看类的定义来判断它的依赖关系是什么,因为它们没有被注入,而是被从服务定位器中拉出来).
所以,你的问题是:为什么服务定位器好?我的回答是:他们不是.
避免,避免,避免.