当一个方法有太多的参数?

在今天debugging一些Web服务客户端代码时(使用Java,使用jax-ws),我跑了一个令人兴奋的97参数的Web服务方法!

我不得不创build一个testing用例来调用这个方法,我注意到了几件事情:

  • 代码辅助/hover不能很好地扩展。 我正在使用Eclipse,方法上的工具提示与屏幕一样宽,并跨越多行。
  • 我不得不从以前的xml捕获中复制参数值,并且实际上不可能记住“我在哪里” – 当光标位于逗号后面并且键入某个值之前,我经常会得到数据types错误 – 我input了一个整数而不是一个string,反之亦然。
  • 即使在我写完所有参数之后,我仍然有一些错误,签名不匹配。 不幸的是,Eclipse将整条线标记为红色,因为发生了错误,所以find错误的地方花了更多时间:(

所以这让我想到了,你认为一个方法的参数的最大数目是多less? 如果你可以改变这个networking服务签名,你觉得它可以改进吗?

没有明确的限制,但是对于超过3-4个参数我感到不舒服。 AFAIR 清洁代码 Bob Martin叔叔推荐最多3个。

有几个重构来减less方法参数的数量(有关细节,请参阅Michael Feathers的有效使用遗留代码 )。 这些出现在我的脑海里:

  • 将许多相关参数封装到单个对象中(例如,而不是String surName, String firstName, String streetAddress, String phoneNumber传递一个包含这些字段的Person对象)
  • 在调用此方法之前,在构造函数或其他方法调用中传递参数

当你不得不问,这可能太多了。

正如Steve McConnell在Code Complete中提到的,黄金法则是4 +/- 3个参数。 对于普通人来说,很难记住超过4个参数,在特殊情况下应该使用5-7,而不应该使用8或更多。

大佛! 九十七????

良好的做法通常build议最大。 六点到八点。 当然,ymmv,也有可能是有原因的,不时有九分之一。 但97 ??!

有一些想法……这些简单的数据,还是根据它们的价值做出的决定?

如果很多/最影响stream量控制,则几乎不可维护(甚至是可理解的或可testing的)“devise”(对于“devise”的小值)。

如果它们只是数据,那么它们可以被分组到结构中吗?

你有任何devise文件吗? 可能会解释发生了什么事。

哦,威尔·罗宾逊(Dan Robinson) – 任何能够公开传递97个参数的人都可能通过任何数量 – 不是那么明显 – 作为全局variables。

Ps不知道Eclipse如何在Java上工作,但是使用C / C ++,如果你把paramaeters放在不同的行上

 char DoEverything( int meaninglessParameterName1, char *meaninglessParameterName2, .... long double *meaninglessParameterName97) { return !NULL;} 

Eclipse实际上将识别具有不良参数的行

那么,如果你使它成为一个JSON对象,那么你可以把所有的97​​(或更多)包装在那个对象中,只发送一个对象。

如果它的参数超过了5到10个,那么创build一个接受参数的对象,它可能是一个types化的数据集,结构或者其他的东西。

代替 :

 Mywebservice.CreateUser(Firstname, LastName, Age,Sex, Haircolor,AmountOfFingers,AmountOfTeeht,Childrens,,,,,,,,,,,,,and so on) 

做:

 Dim MyUser as new UserObject MyUser.Firstname="Stefan" ...and so on... MyWebservice.CreateUser(UserObject) 

根据我自己的经验,我发现方法签名开始变得混乱,难以记忆超过5或6个参数。 而一旦你得到了10个参数,这只是荒谬的。

这些参数确实需要组合成一个包含所有数据的对象(或一组对象)。 在我使用的服务中,每个服务操作总是接受一个Request对象并返回一个Response对象。

就Web服务而言,我更喜欢将参数作为一个单独的对象来处理。 虽然您的数据合同可能会更改,但您的服务合同不会。 这使您的服务更具前瞻性。

对于其他所有的事情,我只有3个参数,并且高达5个。

那么,我会build议重载该方法,以便您有更简单的方法实现。 如果很多参数很less变化,那么这可能特别有用,并且可以指定为默认值。 但是,如果内存服务,我不认为你可以重载Web服务调用(你必须使用一个独特的方法名称)。

另一个可能的解决scheme是将参数封装到某种types的元数据类中,其目的是保存参数。 这将简化方法签名。 但是,在某些方面,您只是将问题卸载到参数类。 但是,如果参数可以分类为主题,则可以通过利用几个元数据类来采用这种技术,每个元数据类将被包括作为Web服务的参数。 这应该简化一些东西,并帮助你把头靠在这个怪物身上。

最后,很难说没有任何细节,但是肯定会出现这个代码是重构的一个重要候选人。 对于一种方法的参数数量,我没有一个硬性规定,而是遵循简单和可读性的一般原则。