最近,我在其中一个项目中发现了非常强大的代码味道,我正在努力。
特别是在其成本计算功能方面。要计算某些操作的总成本,我们必须将许多类型的信息传递给“解析器类”。
例如:
在重构之前,所有这些参数都通过构造函数传递给Counter类(8个参数,你可以想象......)。
为了提高可读性,我引入了一个名为CostCountingData的Data类,其中包含所有这些属性的可读getter和setter。
但我认为,在重构之后,该代码变得更具可读性:
$cost_data = new CostCountingData();
$cost_data->setNumbers($numbers);
$cost_data->setContacts($contacts);
$cost_data->setGroups($groups);
$cost_data->setCampaigns($campaigns);
$cost_data->setUser($user);
$cost_data->setText($text);
$cost_data->setTotalQuantity($total_quantity);
$CostCounter = new TemplateReccurentSendingCostCounter($cost_data);
$total_cost = $CostCounter->count();
您能否告诉我此代码段的可读性是否存在问题? 也许你可以看到任何代码味道,并可以指向我...
我有如何重构此代码的唯一想法是将这个大数据对象拆分为多个,包括相关的数据类型。但我不确定我是否应该这样做..
你怎么看待它?答案 0 :(得分:3)
如果您想要的是命名参数(它在我看来是您想要实现的),您是否会考虑传入一个关联数组,名称为键?还有命名参数成语I can only find a good reference for this for C++ though,也许它被PHP程序员称为其他东西。
为此,您将在CostCountingData上更改方法,以便它们都返回原始对象。这样你就可以重写你的顶级代码:
$cost_data = new CostCountingData();
$cost_data
->setNumbers($numbers)
->setContacts($contacts)
->setGroups($groups)
->setCampaigns($campaigns)
->setUser($user)
->setText($text)
->setTotalQuantity($total_quantity);
所以有两种选择。我可能会自己选择命名参数idiom,因为它是自我记录的,但我不认为差别太大。
答案 1 :(得分:1)
如果我需要数据对象(以及称为“数据”的类本身就是一种气味),我会在其构造函数中设置其值。但有趣的问题是这些价值来自哪里?值的来源本身应该是某种对象,它可能是你真正感兴趣的对象。
编辑:如果数据来自POST,那么我会让这个类成为POST数据的包装器。我不会提供任何setter函数,并且会使读取访问器看起来像这样(我的PHP不仅仅是生锈了):
class CostStuff {
constructor CostStuff( $postdata ) {
$mypost = $postdata;
}
function User() {
return $mypost[ "user_name" ];
}
...
}
答案 2 :(得分:1)
这里有一些可能性:
如果您每次只需要一些参数,那么本答案中其他地方建议的named parameter approach是一个很好的解决方案。
如果您总是需要所有参数,我会建议气味来自计算成本所需数据的破坏语义模型。
无论你如何打电话给一个带有八个论点的方法,事实上需要八个据称不相关的信息来计算某些东西。
退后一步:
八个单独的参数是否真的都是无关的,或者你能组合反映现实情况的中间对象好一点吗?产品?发票项目?还有别的吗?
是否可以将成本方法拆分为较小的方法,根据较少的参数计算部分成本,以及通过累加组件成本产生的总成本?
答案 3 :(得分:0)
您认为您的代码段有什么问题?如果您已经使用了几个变量,现在需要进入$ cost_data,那么您需要依次设置每个变量。没有办法解决这个问题。
问题是,为什么你有这些变量$ number,$ contracts等,你现在决定你需要进入$ cost_data?
您正在寻找的重构可能是您设置$ number的代码中的点实际上应该是您设置$ cost_data->数字的点,并且拥有$ numbers变量是多余的?
E.g。
$numbers=getNumbersFromSomewhere() ;
// do stuff
$contracts=getContracstFromSomewhere() ;
// do stuff
$cost_data=new dataObject() ;
$cost_data->setNumbers($numbers);
$cost_data->setContracts($contracts) ;
$cost_data->someOperation() ;
变为
$cost_data=new dataObject() ;
$cost_data->setNumbers(getNumbersFromSomewhere()) ;
// do stuff
$cost_data->setContracts(getContractsFromSomewhere()) ;
// do stuff
$cost_data->someOperation() ;