【问题标题】:Laravel 4: Facade vs DI (when to use)Laravel 4:外观与 DI(何时使用)
【发布时间】:2013-10-05 03:05:29
【问题描述】:

我的理解是外观被用作依赖注入的替代方案。如果我弄错了,请纠正。尚不清楚何时应该使用其中一种。

每种方法的优点/缺点是什么?我应该如何确定何时使用其中一种?

最后,为什么不两者都用呢?我可以创建一个引用接口的外观。 Sentry 2 似乎是这样写的。有最佳做法吗?

【问题讨论】:

    标签: dependency-injection laravel laravel-4


    【解决方案1】:

    立面

    Facades 不是依赖注入的替代方案。

    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 container 自动注入。所以,当你创建一个 MyClass 的实例时,Laravel 会自动创建一个 MyOtherClass 的实例,并将其放入变量 $class 中。

    依赖注入只是开发人员创建的一个奇怪的行话,用于执行“自动生成参数”这样简单的事情。

    何时使用一个或另一个?

    如您所见,它们是完全不同的东西,因此您无需在它们之间做出决定,但您必须决定在应用程序的不同部分中将其中一个或另一个放在哪里。

    使用 Facades 来简化您编写代码的方式。例如:为您的应用程序模块创建包是一种很好的做法,因此,为这些包创建外观也是一种使它们看起来像 Laravel 公共类并使用静态语法访问它们的方法。

    每次你的类需要使用来自另一个类的数据或处理时使用依赖注入。它将使您的代码可测试,因为您将能够将这些依赖项的模拟“注入”到您的类中,并且您还将行使single responsibility 原则(查看SOLID principles)。

    【讨论】:

    • 在您的示例中,MyOtherClass 的类型提示不是违背了 DI 的观点吗?
    • @WesleyMurch 不!例如,如果没有 DI,您可以将 MyOtherClass 的构造函数参数作为 MyClass 构造函数参数,然后在 MyClass 构造函数中创建 MyOtherClass 的实例。现在 MyClass 对 MyOtherClass 有一个“隐藏的依赖”。 DI 将其翻转过来,因此 MyOtherClass 在外部创建并注入,并且 MyClass 的构造函数签名声明了依赖关系——不再隐藏。键入提示接口意味着您可以编写 MyClass 构造函数,假设您正在使用 MyOtherClass 就像您在那里创建实例一样可靠。
    • 我看不出区别。与依赖注入一样,您可以构建 Facades 的模拟,因此您的代码仍然是可测试的,并且依赖关系仍然可以使用 IoC 容器解决。实际上,它们只是 IoC 容器的“静态”访问器。我看到的唯一区别是,通过使用依赖注入,您可以依赖接口,而使用 Facades,您可以依赖类。你能澄清一下吗?
    • 服务定位器模式反对依赖注入。您在编写类、控制器等时选择其中一个。
    • @Antonio - taylorotwell.com/response-dont-use-facades - “服务位置会导致开发人员养成一些不良的架构习惯”,“它担心的事情太多了。”这确实有道理。我在想——我对课堂有多少依赖。我在构造函数中数 6,+ 4 作为外墙。所以总共有10个依赖项。最好保留大约 4 个。那么我应该将外观视为依赖项吗?我想我应该
    【解决方案2】:

    如前所述,外观旨在简化可能复杂的界面。

    外墙仍然可以测试

    Laravel 的实现更进一步,允许您定义 Facade “指向”的基类。

    这使开发人员能够“模拟”外观 - 通过使用模拟对象切换基类。

    从这个意义上说,您可以使用它们并且仍然拥有可测试的代码。这就是 PHP 社区中存在一些混乱的地方。

    DI 经常被引用为使您的代码可测试 - 它们使模拟类依赖关系变得容易。 (旁注:接口和 DI 存在的其他重要原因!)

    另一方面,Facades 经常被引用为使测试更难,因为您不能“简单地将模拟对象注入”到您正在测试的任何代码中。但是,如前所述,您实际上可以“模拟”它们。

    立面与 DI

    这就是人们对 Facades 是否可以替代 DI 感到困惑的地方。

    从某种意义上说,它们都向您的类添加了依赖项 - 您可以使用 DI 添加依赖项,也可以直接使用 Facade - FacadeName::method($param);。 (希望您没有直接在另一个 :D 中实例化任何类)。

    这并没有使 Facades 成为 DI 的替代品,但相反,在 Laravel 中,确实创造了一种情况,您可以决定以两种方式之一添加类依赖项 - 使用 DI 或使用 Facade。 (当然,您可以使用其他方式。这“两种方式”只是最常用的“可测试方式”)。

    【讨论】:

      【解决方案3】:

      Laravel 的 Facades 是 Service Locator 模式的实现,而不是 Facade 模式。

      在我看来,您应该避免在您的域中使用服务定位器,选择仅在您的服务和 Web 传输层中使用它。

      http://martinfowler.com/articles/injection.html#UsingAServiceLocator

      【讨论】:

      • 是的,当然。我的答案是一个非常古老(并且部分错误)的答案。刚刚编辑以正确说明。
      【解决方案4】:

      我认为 laravel Facades 可以帮助您保持代码简单且仍然可测试,因为您可以模拟外观但是如果您使用外观可能会更难告诉控制器依赖关系,因为它们可能无处不在代码。

      使用依赖注入,您需要编写更多代码,因为您需要处理创建接口和服务来处理依赖关系,但是稍后关于控制器所依赖的内容会更加清楚,因为控制器构造函数中明确提到了这些.

      我想这是决定您喜欢使用哪种方法的问题

      【讨论】:

        猜你喜欢
        • 2013-12-17
        • 2015-07-09
        • 2021-07-22
        • 2013-01-20
        • 2013-06-10
        • 1970-01-01
        • 2014-02-17
        • 2016-06-20
        相关资源
        最近更新 更多