我的理解是外观被用作依赖注入的替代方案。如果我弄错了,请纠正。尚不清楚何时应该使用其中一种。
每种方法的优点/缺点是什么?我应该如何确定何时使用其中一种?
最后,为什么不同时使用两者?我可以创建一个引用接口的外观。Sentry 2 似乎是这样写的。有最佳实践吗?
我的理解是外观被用作依赖注入的替代方案。如果我弄错了,请纠正。尚不清楚何时应该使用其中一种。
每种方法的优点/缺点是什么?我应该如何确定何时使用其中一种?
最后,为什么不同时使用两者?我可以创建一个引用接口的外观。Sentry 2 似乎是这样写的。有最佳实践吗?
外墙
门面不是依赖注入的替代品。
Laravel Facade 是 Service Locator Pattern 的一个实现,它创建了一种简洁美观的访问对象的方式:
MyClass::doSomething();
这是静态方法的 PHP 语法,但 Laravel 改变了游戏规则,让它们在幕后变成非静态的,为您提供了一种漂亮、愉快和可测试的方式来编写应用程序。
依赖注入
基本上,依赖注入是一种将参数传递给构造函数和方法同时自动实例化它们的方法。
class MyClass {
private $property;
public function __construct(MyOtherClass $property)
{
/// Here you can use the magic of Dependency Injection
$this->property = $property
/// $property already is an object of MyOtherClass
}
}
更好的构造方法是在依赖注入的构造函数上使用接口:
class MyClass {
private $property;
public function __construct(MyInterface $property)
{
/// Here you can use the magic of Dependency Injection
$this->property = $property
/// $property will receive an object of a concrete class that implements MyInterface
/// This class should be defined in Laravel elsewhere, but this is a way of also make
/// your application easy to maintain, because you can swap implementations of your interfaces
/// easily
}
}
但请注意,在 Laravel 中,您可以以相同的方式注入类和接口。要注入接口,你只需要告诉它一个将是这样的:
App::bind('MyInterface', 'MyOtherClass');
这将告诉 Laravel,每次你的方法之一需要一个 MyInterface 实例时,它应该给它一个 MyOtherClass。
这里发生的是这个构造函数有一个“依赖”:MyOtherClass
,它将由 Laravel 使用IoC 容器自动注入。因此,当您创建 的实例时MyClass
,Laravel 会自动创建 的实例MyOtherClass
并将其放入变量中$class
。
依赖注入只是开发人员创建的一个奇怪的行话,用于执行诸如“自动生成参数”之类的简单事情。
何时使用一个或另一个?
正如你所看到的,它们是完全不同的东西,所以你永远不需要在它们之间做出决定,但你必须决定在你的应用程序的不同部分中将一个或另一个放在哪里。
使用 Facades来简化您编写代码的方式。例如:为您的应用程序模块创建包是一种很好的做法,因此,为这些包创建外观也是一种使它们看起来像 Laravel 公共类并使用静态语法访问它们的方法。
每当您的类需要使用来自另一个类的数据或处理时,请使用依赖注入。它将使您的代码可测试,因为您将能够将这些依赖项的模拟“注入”到您的类中,并且您还将行使单一职责原则(查看SOLID 原则)。
如前所述,外观旨在简化可能复杂的界面。
Laravel 的实现更进了一步,它允许你定义 Facade “指向”的基类。
这使开发人员能够“模拟”外观 - 通过使用模拟对象切换基类。
从这个意义上说,您可以使用它们并且仍然拥有可测试的代码。这就是 PHP 社区中存在一些混乱的地方。
DI 经常被引用为使您的代码可测试 - 它们使模拟类依赖关系变得容易。(旁注:接口和 DI 存在的其他重要原因!)
另一方面,Facades 经常被引用为使测试更加困难,因为您不能“简单地将模拟对象注入”到您正在测试的任何代码中。但是,如前所述,您实际上可以“模拟”它们。
这就是人们对 Facades 是否可以替代 DI 感到困惑的地方。
从某种意义上说,它们都向您的类添加了依赖项 - 您可以使用 DI 添加依赖项,也可以直接使用 Facade - FacadeName::method($param);
。(希望您没有直接在另一个 :D 中实例化任何类)。
这并没有使 Facades 成为 DI 的替代品,但相反,在 Laravel 中,确实创造了一种情况,您可以决定以两种方式添加类依赖项 - 使用 DI 或使用 Facade。(当然,您可以使用其他方式。这“两种方式”只是最常用的“可测试方式”)。
Laravel 的 Facades 是 Service Locator 模式的实现,而不是 Facade 模式。
在我看来,您应该避免在您的域中使用服务定位器,选择仅在您的服务和 Web 传输层中使用它。
http://martinfowler.com/articles/injection.html#UsingAServiceLocator
我认为就 laravel Facades 而言,它可以帮助您保持代码简单且仍然可测试,因为您可以模拟外观但是如果您使用外观可能会更难告诉控制器依赖关系,因为它们可能在您的代码中无处不在。
使用依赖注入,您需要编写更多代码,因为您需要处理创建接口和服务来处理依赖关系,但是稍后关于控制器所依赖的内容会更加清楚,因为控制器构造函数中明确提到了这些。
我想这是决定您喜欢使用哪种方法的问题