【问题标题】:Are Laravel facades dependencies?Laravel 门面是依赖项吗?
【发布时间】:2015-05-31 10:31:15
【问题描述】:

我已经读到一个类不应该有太多的依赖关系。在一本书中,它指出 4 个依赖项可能表明类可能做得太多。

假设我编写了一个使用 10 个依赖项的类:6 个类和 4 个外观。我应该只关心这 6 个类并拆分它们,还是也关心 4 个外观?

如果有人想知道我是如何得到这么多外墙的:

use Input;
use App;
use Session;
use Log;

这些都是经常需要的。我听说过一个问题 - 为什么我需要应用程序?调用函数:

App::setLocale('lt');

有人说门面不是依赖,也在这里:

Polymorphism and dependency injection - too many dependencies

关于这个问题有很多不同的看法(什么时候上课 依赖于某些东西),但类依赖通常被视为 传递给构造函数的内容,即类所需的内容 被实例化为一个对象。

我想我可以自己从一个类中创建一个外观,我会通过这种方式减少依赖关系。但这有意义吗?

例如这篇文章指出 - 我们不应该使用外观:

http://taylorotwell.com/response-dont-use-facades/

据我了解,外观不会那么糟糕,但糟糕的是类开始做太多事情。

我说的是 Laravel 4,但可能同样适用于 Laravel 5 或其他使用相同的框架。我刚刚听说 Laravel 5 使用的门面没有 Laravel 4 那么多。

更新:

我也想得到这样的论据,以便在讨论这个话题时可以与其他人一起使用。就像我说的那样-互联网上的某个人(即使具有良好的stackoverflow配置文件)对我说外观很糟糕,它们就像全局变量,它们会立即告诉您-这与全局不同,它们是可模拟的,您不应该关心。他们也可能会说,这是那些家伙的意见。所以我想要一个强项来保护自己。所以我可以把它解释为 2*2 = 4 并且没有人会不同意。或者至少接近那个。

更新:

如果这些是依赖项,并且我希望一个类最多有 4 个依赖项,我只有一个想法 - 创建分组类,就像类树一样。但我最终得到了许多用于小功能的类。就像这 10 个依赖项一样,如果我想拥有最多 4 个依赖项,我想我需要 3-5 个类而不是 1 个。所以如果我有大项目,你将拥有数百万个小类。那它看起来不会更复杂吗?就像我看到的 Laravel 有很多类,而 CodeIgniter 的类少得多,并且看起来更易于阅读/遵循、扩展。

【问题讨论】:

  • 它们依赖关系。他们被“给予”任何需要的方式是最糟糕的方式。考虑到 laravel 为一个类提供了一个包含很多废话的整个容器(App),其中一些内容是依赖项。容器的其他内容是无用的废话,您可以从任何地方访问它们,因为它是一个可怕的实现。
  • “据我所知,外墙不会那么糟糕”你理解错了。它与使用 global 关键字的大部分问题相同。另请注意,Foo::bar()$app['foo']->bar() 基本上都是废话。相关帖子:stackoverflow.com/questions/11923272/…
  • @PeeHaa - 在您的示例主题中 - 我看到了不同之处:$db 被硬编码到类中,而 laravel 外观可以被模拟。全局变量的问题我发现它们可能会发生冲突,但我自己没有这个问题,因为我没有创建自己的外观。
  • 它仍然是一个隐藏的依赖关系。你不可能知道(通过查看方法签名)它具有特定的依赖关系。

标签: php single-responsibility-principle laravel-facade


【解决方案1】:

Laravel 外观绝对是依赖项,它们的预期用途是用于控制器,在构建服务和业务逻辑时,您应该尝试使依赖项尽可能透明。

如果您的目标是实现 SOLID 实现,您将希望将所有依赖项作为参数或在类构造函数中传递。

让我们稍微说明一下这个抽象:

重构前

Class PhotoService {

    protected $photosModel = null;

    public function getPhotos()
    { 
        $photos = Cache::get('photos');

        if (is_null($photos)) {
           return Photo::all();
        }
    }
}

仍然使用外观,但通过 IOC 解决其他依赖项

Class PhotoService {

    protected $photosModel = null;

    public function __construct(PhotoInterface $photoModel) {
       $this->photosModel = $photoModel;
    }

    public function getPhotos()
    {
       $photos = Cache::get('photos');

       if (is_null($photos)) {
          return $this->photosModel->getPhotos();
       }
    }
}

通过国际奥委会解决

Class PhotoService {

    protected $photosModel = null;

    public function __construct(PhotoInterface $photoModel) {
       $this->photosModel = $photoModel;
    }

    public function getPhotos(CacheInterface $cache)
    {
       $photos = $cache->get('photos');

       if (is_null($photos)) {
          return $this->photosModel->getPhotos();
       }
    }
}

在我看来,最好的例子是外部化代码,即使您在自己的项目之间共享代码也是如此。如果新实现通过接口提供了完整签名,则它更容易工作,而不必查看旧代码或测试任何外观。

不过,我认为在控制器中使用 Facades 没有任何害处。

这种设置只提供优势,它们之间:

  • 无需头疼即可切换缓存策略
  • 切换数据库类型的能力
  • 通过 ioc 注入模拟来关闭功能的能力
  • 通过易于实施来鼓励 tdd

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-24
    • 2017-06-23
    • 1970-01-01
    • 2013-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多