#1 楼
马丁·福勒(Martin Fowler)的圣经书《重构》确实识别出一种叫做“长参数列表”(p78)的气味,并提出了以下重构方法: >引入参数对象(295)
保留整个对象(298)
其中我认为“引入参数对象”最适合:
将属性包装在自己的对象中,然后将其传递给构造函数。如果您选择将所有值直接捆绑到其构造函数中,则可能会遇到与新对象相同的问题,尽管您可以在该对象中使用setter而不是参数。 PHP-fu较弱):您担心不清楚属性的目的/含义。同样,稍后在方程式中添加额外的属性也不会那么麻烦。
#2 楼
除了LRE的答案,我建议您考虑一下这样的想法,即您的类需要大量的构造函数参数,因为它试图做太多事情。#3 楼
正如@LRE答案(+1)所述,他的PHP-fu很弱,并且由于他的观点是正确和有效的,我只想提供更多php代码来说明:#4 楼
我认为最好将所有参数放入一个数组中。然后,当您要调用构造函数时,可以在单个命令中构造数组。这种方法的好处还在于可以为该类添加更多选项,请参见下面的示例:
class OpenIdProvider
{
public $_width = 0;
public $_highliting = '';
public $_Xposition = 0;
public $_Yposition = 0;
...
...
/**
* Main constractor to set array of parameters.
* param array $parameters
* description _Xposition , _width , _Yposition ...
*/
function __constrauct($parameters)
{
if(is_array($parameters))
foreach($parameters as $needle=>$parameter)
$this->{'_'.$needle} = $parameter;
}
}
$options = array('path'=>$imgPath . $name . $ext,
'highliting'=> 'openid_highlight',
'width'=>108,
'height'=>68,
'...'=>6,
'...'=>$info[0],
'...'=>$info[1],
'...'=>$name);
$openIdObj = new OpenIdProvider($options);
评论
\ $ \ begingroup \ $
我真的很不喜欢它,原因有很多:没有类的类型提示,没有必需的必需参数,因此最重要的是您需要进行更多的错误检查:难以置信的难以使用,植入很容易,但是api却遭受了很大的损失。您甚至需要至少重复一下doc块中的所有参数,您甚至有机会无需查看源代码就可以创建类。尽管如此,阅读文档并独自构建一个晦涩难解的内容足以让我不喜欢:)仍然:感谢您的分享,尽管如此
\ $ \ endgroup \ $
– edorian
2011年1月24日,12:24
\ $ \ begingroup \ $
@edorian可以详细说明吗?这就是我目前工作中大量遗留代码的工作方式,我试图理解为什么这是错误的,什么更好。您基本上是在说像这样难以维护的只是浮游的params数组吗?这些对象提供了更多的结构并且更加标准化了?您能解释一下文档的阻止点吗?
\ $ \ endgroup \ $
– Sam Selikoff
13年5月9日在16:33
\ $ \ begingroup \ $
请注意,此类允许在OpenIdProvider中设置任意变量。 $ this-> {'_'。$ needle} = $ parameter;这将创建您喜欢的任何带下划线前缀的变量。即使这只是潜在的不安全因素,也可能导致“典型”错误。如上面实际代码中的“突出显示”所示!那会默默地创建$ this-> _ highliting而不是设置$ this-> _ highlighting
\ $ \ endgroup \ $
–TomášFejfar
17-3-29在20:20
#5 楼
PHP数组功能强大。与highelf相似,我将使用数组。收到的数组(尤其是使用未知的数组键)。检查收到的值。
如edorian所说,没有类型提示,但是您可以手动执行所需的参数。这种方法的优点是:
很容易记住参数的数量(1)。
参数的顺序不再重要。 (尽管按字母顺序可以很好地工作,但不必担心保持一致的参数顺序。)
随着参数的命名,调用代码更具可读性。高度,即使类型相同。 (这很容易被类型提示忽略)。
所以这就是我要做的事情:
#6 楼
有同样的问题。这是我的解决方案:尽最大的努力将您的类分解为各种片段。例如,似乎您的对象绘制了自己的图像。将其委托给另一个类(IOpenIDImage)。如果提供程序应该打开框架或选项卡来执行其工作,那么请使用另一个IOpenIDFrame类。
现在您的代码将变为:
这使您的代码:
更小/紧凑。更容易理解。
更容易调试。由于所有内容均位于单独的区域中。
更易于测试。您可以测试图像等不同方面。
易于修改。您不必修改整个类。
我遵循以下规则:
2函数优于1
2类优于1
2变量优于1
#7 楼
您可以在此处使用构建器模式。我强烈建议在其中引入流利的接口。这里有stackoverflow链接
当设计其构造函数或静态工厂将具有更多功能的类时,构造器模式是一个不错的选择。而不是少数几个参数。
最后,您会看到类似
$op = new OpenIdProviderBuilder()
.setImagePath($imgPath . $name . $ext)
.setOpenId('openid_highlight')
.setX(0)
.setY(0)
.setR(100)
.setG(80)
.setB(120)
.setInfo("some info");
评论
\ $ \ begingroup \ $
谢谢,非常有帮助。那么,是否建议使用参数对象而不是使用默认构造函数实例化我的对象并直接在该对象上调用setter呢?
\ $ \ endgroup \ $
– BenV
2011年1月22日,下午5:01
\ $ \ begingroup \ $
@BenV,您可以选择其中任何一种方式。我仔细研究了这两种方法,并选择了使用参数对象,因为它将管理设置的问题与提供者分开了,后者的责任不同。
\ $ \ endgroup \ $
– LRE
2011年1月22日,下午5:05
\ $ \ begingroup \ $
我将直接使用“用方法替换参数”,从构造函数中删除所有/大多数参数,并添加getter / setter。至少如果所提供的参数集中没有明确的语义,例如OpenIDParams似乎并没有在这里增加太多,它只是解决了问题:“我是否需要一个具有OpenIDParams所有这些参数的构造函数?” ...更高层次的抽象并不总是可以解决问题:)
\ $ \ endgroup \ $
– EricBréchemier
2011-1-22在8:58
\ $ \ begingroup \ $
在带有对象常量(javascript):new OIDP({“ arg1”:val1,“ arg2”:val2 ...}的语言中,这特别好用。类似的可读性提高在具有关键字参数(如python)的语言中也有效。在这两种情况下,您都可以得到非常紧凑且易读的内容(关键字strategy并不真正对应于参数对象,但是读取得足够近,以至于我认为我会包含它)。
\ $ \ endgroup \ $
–卡斯特马
2011年1月22日在16:44
\ $ \ begingroup \ $
在专门重构构造函数之前,还请问一下自己:这些参数中的任何一个都可以归类为有用的东西吗?也许所有这些数字都是相关的,您可以从中创建一个对象吗?这将减少构造函数的参数数量,并通常为您提供更好的可读性,同时在一个地方可以重用而不仅仅是一个构造函数。
\ $ \ endgroup \ $
–塞巴斯蒂安·雷德尔(Sebastian Redl)
14年2月24日在16:09