用于消除 Symfony2 中重复代码的特征、辅助服务或继承

Posted

技术标签:

【中文标题】用于消除 Symfony2 中重复代码的特征、辅助服务或继承【英文标题】:Traits, helper service or inheritance for eliminating repetitive code in Symfony2 【发布时间】:2015-09-25 22:35:44 【问题描述】:

我正在尝试清理大部分代码都在控制器内部的旧 Symfony2 项目。控制器中冗长、重复的代码块并不是最优的,它使调试和开发变得非常乏味且容易出错。

有很多东西我可以轻松清理并转移到服务中,因为这些代码块提供了某种可重用的功能。我知道任何定义明确的任务都应该存在于服务中,而控制器应该只是“接线”。

但是,无论我将代码移到哪里,总会有小的重复块将所有内容弄得一团糟。例如,在我们的应用程序中广泛使用的初始化/转换/解析/过滤模式之类的东西。

以创建DataTable所需的数据“揉捏”为例:

class DefaultController extends Controller 

    public function indexAction() 

        $data = array(/* some data */);

        $encoders = array(new JsonEncoder());
        $normalizers = array(new GetSetMethodNormalizer());
        $serializer = new Serializer($normalizers, $encoders);
        $datatable = $this->get('datatables.orders');
        $datatable->buildDatatableView();
        $datatable->setData($serializer->serialize($data, 'json'));

        return array('datatable'=>$datatable);
    

这是一种非常常见但也非常冗长的模式。我们的开发人员倾向于将数十种此类小模式存储在自己计算机上的文本文件中,并经常将它们复制/粘贴到控制器中。

如果我尝试想办法让代码更简洁(和 DRY),有多种选择。

我可以从所有操作中过滤掉重复的模式并将它们转储到私有函数中。我已经在某些地方进行了此操作以稍微清理一下,但这是一个针对每个控制器本地化的糟糕解决方案。 我可以使用所有这些代码 sn-ps 和use 在服务或控制器中创建一个或多个通用“帮助器”类,只要我需要它们在服务或控制器中,包含各种解析/检查/过滤/构建功能。不过,它可能会变成微小的无关方法的垃圾收集。 我可以创建一个或多个抽象类,其中包含许多服务/控制器中使用的属性/方法,并从中继承。感觉很老套,尤其是当我需要将它夹在用户定义的控制器和 Symfony 框架控制器类之间时。 我可以为这些数据转换函数定义特征,并在适用的地方使用它们。人们经常声称 php 特性几乎总是不好的。但是,对我来说,特质似乎是最不滥用且最简洁的选择。

考虑一下:

Bundle/Traits/TableTrait.php

Trait TableTrait 
    function serialize($data, $format)
        $encoders = array(new JsonEncoder());
        $normalizers = array(new GetSetMethodNormalizer());
        $serializer = new Serializer($normalizers, $encoders);
        return $serializer->serialize($data, $format);
    

    function buildTable($table, $data)
        $datatable = $table;
        $datatable->buildDatatableView();
        $datatable->setData($this->serialize($data, 'json'));
    

Bundle/Controller/SomeController.php

class DefaultController extends Controller 

    use \Bundle\Traits\TableTrait;

    public function indexAction() 

        $data = array(/* some data */);
        $datatable = $this->buildTable($this->get('datatables.orders'),$data);

        return array('datatable'=>$datatable);
    

这将 6 行样板代码减少到 1 行。

特征是不是一个糟糕的解决方案? 如果是这样,哪些选项会更好?

【问题讨论】:

这似乎很好地使用了AppBundle\Utils 命名空间。我不知道trait 比一组定义明确的实用程序类更有意义;无论如何,您都在使用use,这些是否是“特征”是有争议的。是什么让你的特征也不会变成不相关功能的垃圾收集? 完全正确。我以某种方式将特征与较小的、不太紧密相关的功能联系起来……在我看来,服务是一件大事,比如邮局(在 symfony 中,例如处理所有电子邮件),而特征将定义街道需要邮箱的事实(在另一个控制器或服务中初始化邮件服务)。这作为一个比喻很有效,但我不知道这个假设背后是否有任何实际的逻辑/真相。 【参考方案1】:

您可能会考虑将一些东西转移到服务中。例如:

$serializer = $this->get('json.getset.serializer');

也许做一个数据表工厂服务

$dataTable = $this->get('datatable.orders.factory')->create($data);

您甚至可以更进一步,将您的控制器定义为服务,然后注入所需的依赖项。所以你最终会得到:

$dataTable = $this->dataTableFactory->create($data);

【讨论】:

以上是关于用于消除 Symfony2 中重复代码的特征、辅助服务或继承的主要内容,如果未能解决你的问题,请参考以下文章

递归特征消除(RFE)+ 交叉验证

用于分类和回归的递归特征消除的模型

怎样消除公司的信息孤岛

消除数据库中的重复项

用于使用序列消除重复条目的 Oracle PLSQL 更新查询

随机森林的REF递归特征消除法来筛选特征(python实现不依赖sklearn)