正在传递大量参数给parent::__construct一个代码难闻/糟糕的OOP


Is passing a lot of parameters to parent::__construct a code smell/poor OOP?

我正在写一些代码,我开始对混乱的parent::__construct调用感到有点不舒服,我想知道首先是糟糕的OOP实践,其次是有更干净的方法来做到这一点?请看下面这个引发我的问题的特别极端的例子。

<?php
class BrowseNodeLookupRequest extends Request {
    protected $BrowseNodeId;
    public function __construct($Service, $AWSAccessKeyID, $AssociateTag,
            $Operation, $MerchantID = null, $ResponseGroup = null,
            $Version = null, $Style = null, $ContentType = null,
            $XMLEscaping = null, $Validate = null, $BrowseNodeId) {
        parent::__construct($Service, $AWSAccessKeyID, $AssociateTag,
                $Operation, $MerchantID, $ResponseGroup, $Version, $Style,
                $ContentType, $XMLEscaping);
        $this->setBrowseNodeId($BrowseNodeId);
    }
    protected function setBrowseNodeId($BrowseNodeId) {
        if (is_string($BrowseNodeId)) {
            $this->BrowseNodeId = $BrowseNodeId;
        } else {
            throw new Exception('BrowseNodeLookupRequest Parameter (BrowseNodeId
                                 ) Must be a String');
        }
    }
}
?>

对任何函数都有那么多参数是不好的做法,无论是对__parent::construct还是不是。

很容易搞砸,尤其是在PHP中。很多时候,这表明您缺少对象(或者部件之间的耦合太紧)。我甚至更喜欢传递一个"配置"对象,如果你不能想出任何其他缺失的对象。

class ConfigFoo
{
  public $Service, $AWSAccessKeyID, ..., $foo, $bar;
}
$cfg = new ConfigFoo();
$cfg->Service = 'whatever';
...
$req = new BrowseNodeLookupRequest($cfg);

这基本上是传递参数数组的一种更结构化的方式。配置对象可以扩展其他配置对象以跟随您的其他对象。

当然,类可以比简单的公共属性更高级。您可以管理数据完整性,等等。

要清楚:我不会诉诸上述,除非a)没有其他缺少的中间对象和b)有足够数量的参数,使得使用一个简单的数组就像使用一长串函数参数一样有问题。

我觉得参数太多了。我要么传入一个数组,要么可能将关注点分离到不同的模型中,然后通过构造函数将它们注入对象。

调用parent::__construct();

在php中,这可能并不总是必需的,因为如果父类有自己的构造函数,而子类没有定义构造函数,则会自动调用父类的构造函数。

相反,在Java中没有这样的奢侈,你必须在Java中调用父构造函数,所以这是你在Java中经常看到的东西,可能在其他语言中允许重载构造函数方法

感谢所有的注释者,特别是Matthew,我采用的解决方案是从父类的构造函数方法中删除可选参数,并将它们添加到父类中可用的公共setter方法中。下面是修改后的代码和使用示例。注意'->setValidate'和'->setResponseGroup'是继承自父类的新方法。显然,如果您处于类似的情况,但您的所有参数都是必需的,那么您需要选择响应中列出的其他选项之一。

修改类:

<?php
class BrowseNodeLookupRequest extends Request {
    protected $BrowseNodeId;
    public function __construct($Service, $AWSAccessKeyID, $AssociateTag,
            $Operation, $BrowseNodeId) {
        parent::__construct($Service, $AWSAccessKeyID, $AssociateTag, $Operation);
        $this->setBrowseNodeId($BrowseNodeId);
    }
    protected function setBrowseNodeId($BrowseNodeId) {
        if (is_string($BrowseNodeId)) {
            $this->BrowseNodeId = $BrowseNodeId;
        } else {
            throw new Exception('BrowseNodeLookupRequest Parameter (BrowseNodeId
                                 ) Must be a String');
        }
    }
}
?>

使用例子:

<?php
$noderequest = new BrowseNodeLookupRequest($Service, $AWSAccessKeyID, $AssociateTag,
            $Operation, $BrowseNodeId);
//If the optional params are required//
$noderequest->setResponseGroup('Blah');
$noderequest->setValidate('True');
//etc.
?>