使用服务层的特征:这是不好的做法吗?

时间:2018-01-16 11:57:36

标签: php laravel symfony dependency-injection software-design

我注意到laravel程序员通常使用traits在控制器中实现某种依赖注入,而laravel本身也使用很多特性来实现我认为是服务的东西。

我来自symfony,其中特征没有在框架本身中广泛使用,我发现它有点奇怪,因为我发现因为这样的原因使用特征,而不是那么清晰的设计。不应该在自己的班级中定义服务吗?使用特质服务是否可以接受?

2 个答案:

答案 0 :(得分:5)

我注意到之前的答案尚未被接受,所以我想给自己2美分。

同样来自Symfony 2环境,目前正在参与Laravel和准备Symfony 3环境我也正在阅读这个主题,因为我曾经读过这些特性是邪恶的。以下链接有一个已接受的答案,在我看来是一个不那么主观的答案,它做了一些公平的假设,看起来构造得很好:https://codereview.stackexchange.com/questions/74077/trait-accessing-variables-of-classes-using-it

但是,我认为最大的区别可能是默认的Laravel使用ActiveRecord,而不是Symfony使用的Service / Repository层。我个人更喜欢后者,它不那么沉重,更容易实现SOLID,逻辑和数据通常已经解耦,使层更容易交换。无论如何,这是一个不那么主题和非常个人化的说明。

现在在Laravel工作了几个月(相比之下,我在sf2(和sf1)工作多年)我几乎不是Laravel如何工作的专家。就个人而言,我仍然不喜欢特质,因为如果你不至少与它们接触,它们对我来说太神奇了。我经常认为通过其他设计模式可以更好地处理它。

TL; DR :(基本链接的要点)

  • 特征的一个很好的用例是水平扩展,支持独立的操作,而不必在每次添加接口时都必须实现它。 (通常这是相当简单的逻辑)
  • 一个坏的是使用其自身范围内的信息的特征(例如'main'对象的属性,或简称为全局状态),或强制执行/中断合同。

答案 1 :(得分:0)

trait 类似于无法自行实例化的抽象类。

  

Traits是单继承语言中代码重用的一种机制   在这种情况下PHP。

现在每当你发现自己的模型变得过于臃肿并且你在不同的模型中反复使用相同的功能时,你可能会认为使用特征是一个尾迹。

现在你可能会想,因为我们有相同的功能,为什么不使用模板design pattern?!然而,由于Laravel中的所有模型都扩展了基本模型,因此您应该小心使用interitance。

如果你想使用softDeletes(),Laravel默认会使用很多特征示例,然后只需要拉一个特征就可以将函数引入该模型。

这是特质的实际用途。我的一个应用程序发生,我想跟踪我的数据库上发生的所有更新,并将它们存储在不同的表中。因此,如果我想跟踪模型活动,那么我只是使用这个特性:

<?php

namespace App;

use App\Activity;

trait RecordsActivity
{

    protected static function bootRecordsActivity()
    {

        static::created(function ($thread) {
            $thread->recordActivity('created');
        });
    }

    protected function recordActivity($event)
    {
        Activity::create([

            'user_id'      => auth()->id(),
            'type'         => $event . '-' . strtolower((new \ReflectionClass($this))->getShortName()),
            'subject_id'   => $this->id,
            'subject_type' => get_class($this),
        ]);
    }
}

因此,每当我想跟踪模型活动时,我只需简单介绍这个特性,

use RecordsActivity; 

而不是使用额外的代码使模型膨胀,甚至在不同的模型中使用最差的重新代码,或者使用类继承使其更加spageti。

或者在Laravel的某些特性中,当你像softDeletes一样需要它们时,你只需将它们拉进去,而不是在基类中准备它们,即使你不需要它们。