可能违反单一责任原则的控制器?

时间:2014-07-31 20:08:46

标签: model-view-controller dependency-injection solid-principles single-responsibility-principle php-5.5

参考此评论,

  

当一个类有很长的参数列表时,它可以是一个“代码   闻到“你的班级试图做太多而且可能不做   遵循单一责任原则。如果你的班级正在尝试   要做太多,请考虑将您的代码重构为多个   彼此消耗的小班。

我应该怎么做下面这个控制器类 - 它是“试图做太多”?

class Controller
{
    public $template;
    public $translation;
    public $auth;
    public $article;
    public $nav;

    public function __construct(Database $connection, $template) 
    {
        $this->template = $template;
        $this->translation = new Translator($connection);
        $this->nav = new Nav($connection);
        $this->article = new Article($connection);
        $this->auth = new Auth($connection);
    }

    public function getHtml() 
    {
        if(isset($_REQUEST['url'])) 
        {
            $item = $this->article->getRow(['url' => 'home','is_admin' => $this->auth->is_admin]);
            include $this->template->path;
        }
    }
}

如何将它分解为更小的类 - 如果它是一个控制器,它包含我需要输出页面的这些基本类?

我该怎么做才能遵循dependency injection的原则?

2 个答案:

答案 0 :(得分:1)

  

注意:这将是简短版本,因为我正在工作。我将在晚上详细说明

所以...你的代码有以下违规行为:

  • SRP (以及扩展名 - SoC):您的控制器负责验证输入,授权,数据收集,使用数据填充模板以及渲染所述模板。此外,您的Article似乎对数据库抽象域逻辑负责。

  • LoD :您只传递$connection ,因为您需要将其传递给其他结构。

  • 封装:您的所有类属性都具有公开可见性,并且可以随时更改。

  • 依赖注入:当你的"控制器"有几个直接的依赖关系,你只是传递模板(实际上不应该由适当的MVC中的控制器管理)。

  • 全局状态:您的代码取决于$_REQUEST超全局。

  • 松散耦合:您的代码直接绑定到类的名称和这些类的构造函数的足迹,您在构造函数中初始化。

答案 1 :(得分:0)

TL; DR:我在这里看不到违反SRP的情况,但是对象构成有点破坏

从我看到的(这是完整的类列表?),$connection不会直接在类中使用,因此不应该注入它。

我在任何地方都看不到$this->translation$this->nav的使用情况。这是一个复制粘贴工件吗?

而是注入$connection,我会在这个类之外构造ArticleAuth,然后只注入这些,因为你的控制器只直接使用这些,而不是控制器。 所以整个班级都是这样的:

class Controller
{
    private $article;
    private $auth;
    private $template;

    public function __construct(Article $article, Auth $auth, $template) 
    {
        $this->article = $article;
        $this->auth = $auth;
        $this->template = $template;
    }

    public function getHtml() 
    {
        if(isset($_REQUEST['url'])) 
        {
            $item = $this->article->getRow(['url' => 'home','is_admin' => $this->auth->is_admin]);
            include $this->template->path;
        }
    }
}

除非你的Article是具有ActiveRecord模式的域对象,否则在这种情况下我仍会注入$connection并将其存储在本地变量中。并且仅在您确实需要时创建新的Article对象,即在getHtml方法中。

这样你在构造函数中不做太多工作,只分配局部变量。对象组合在其他地方处理。如果需要,您可以替换Auth的实施。

此外,当您在构造函数中没有做太多工作时,您的对象图创建非常便宜。如果你使用某种DI容器,这很重要,因为必须同时创建很多对象。