例程可以有参数,这不是新闻。您可以根据需要定义任意多的参数,但是过多的参数会使您的例程难以理解和维护。

当然,您可以使用结构化变量作为解决方法:将所有这些变量放在单个结构中并将其传递给例程。事实上,使用结构来简化参数列表是Steve McConnell在Code Complete中描述的技术之一。但正如他所说:

谨慎的程序员避免将数据捆绑在一起,除非逻辑上是必要的。

因此,如果你的例程有太多的参数,或者你使用一个结构体来掩盖一个大的参数列表,你可能做错了什么。也就是说,你没有保持耦合松散。

我的问题是,什么时候我可以认为一个参数列表太大?我认为5个以上的参数太多了。你怎么看?


对于我来说,当列表在我的IDE上超过一行时,那么它就是一个参数太多了。我想在一行中看到所有的参数,而不中断眼神交流。但这只是我个人的偏好。


我基本上同意5,但是,如果在我需要更多的情况下,这是解决问题的最清晰的方法,那么我会使用更多。


根据Perl最佳实践,3个是可以的,4个太多了。这只是一个指导方针,但在我们店里,这是我们努力遵守的。


如果您开始在心里计算签名中的参数,并将它们与调用匹配,那么是时候重构了!


似乎除了数字之外还有其他的考虑因素,以下是我想到的一些:

与函数主要目的的逻辑关系vs.一次性设置 如果它们只是环境标志,那么捆绑会非常方便


这很大程度上取决于你工作的环境。以javascript为例。在javascript中,传递参数的最佳方式是使用带有键/值对的对象,这实际上意味着你只有一个参数。在其他系统中,最佳点将是3或4。

归根结底,这一切都取决于个人品味。


作为一般的经验法则,我停留在三个参数上。如果再多,就应该传递一个参数数组或配置对象,这也允许在不更改API的情况下添加未来的参数。


我自己把公共函数的极限画在5个参数上。

恕我直言,长参数列表只适用于私有/本地helper函数,这些函数只能从代码中的几个特定位置调用。在这些情况下,您可能需要传递大量的状态信息,但可读性并不是一个大问题,因为只有您(或维护您的代码并应该了解模块基础的人)必须关心调用该函数。


我想说,只要你有2-4的过载,如果你需要的话,你就可以去更高的地方。


我同意3个是可以的,4个太多了。如果有3个以上的参数,你就不可避免地要做不止一个任务。一个以上的任务应该被分割成不同的方法。

然而,如果我查看我所从事的最新项目,例外情况比比皆是,大多数情况下很难归结为3个参数。


我认为实际的数字取决于函数上下文的逻辑意义。我同意大约4-5个参数开始变得拥挤。

在设置标志的情况下,处理这种情况的一个好方法是枚举值并将它们一起OR。


什么时候被认为如此淫秽的东西可以被监管,尽管第一修正案保证了言论自由?根据波特·斯图尔特法官的说法,“当我看到它的时候,我就知道了。”这里也是一样。

我讨厌制定这样的硬性规则,因为答案不仅取决于项目的大小和范围,而且我认为它甚至会改变到模块级别。这取决于你的方法在做什么,或者这个类应该表示什么,2个参数很可能太多了,这是过度耦合的症状。

我建议通过在第一时间提出这个问题,并尽可能多地限定你的问题,你真的知道所有这些。这里最好的解决方案不是依赖于一个硬性的数字,而是在同行中查看设计评审和代码评审,以确定低内聚性和紧密耦合的领域。

不要害怕向同事展示你的工作成果。如果您害怕,这可能是您的代码有问题的更大迹象,并且您已经知道了它。


在《干净代码》一书中,罗伯特·c·马丁用了四页纸来讨论这个问题。要点如下:

a的理想参数数 函数为零(niladic)。接下来 一个(单体),紧随其后的是两个 (二元)。三个参数(三元) 应该尽量避免。更多的 Than three (polyadic)要求very 特殊理由——然后 反正也不应该用。


这个答案假设使用面向对象语言。如果你不使用,跳过这个答案(换句话说,这不是一个语言不可知的答案。

如果你传递了超过3个左右的参数(特别是内在类型/对象),这并不是“太多”,而是你可能错过了创建一个新对象的机会。

寻找传递给多个方法的参数组——即使是传递给两个方法的参数组也几乎可以保证在那里有一个新对象。

然后,您将功能重构到新对象中,您无法相信它对代码和对OO编程的理解有多大帮助。


我过去使用的一些代码使用全局变量,只是为了避免传递太多参数。

请不要这样做!

(通常)。


A length restriction on a parameter list is just one more restriction. And restriction means applied violence. It sounds funny, but you can be non-violent even when programming. Just let the code dictate the rules. It is obvious that if you have many parameters, the body of the function/class method will be big enough to make use of them. And big code snippets usually can be refactored and split into smaller chunks. So you get solution against having many parameters as free bonus, since they are split among the smaller refactored pieces of code.


多了一个。我并不是说要油嘴滑舌,但是有些函数确实需要一些选项。例如:

void *
mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t offset);

有6个论点,每一个都是必不可少的。此外,它们之间没有共同的联系来证明捆绑销售是合理的。也许你可以定义“struct mapargs”,但那更糟糕。


只有在某些参数是冗余的情况下,函数才可能有过多的参数。如果使用了所有参数,则函数必须具有正确的参数数量。以这个常用的函数为例:

HWND CreateWindowEx
(
  DWORD dwExStyle,
  LPCTSTR lpClassName,
  LPCTSTR lpWindowName,
  DWORD dwStyle,
  int x,
  int y,
  int nWidth,
  int nHeight,
  HWND hWndParent,
  HMENU hMenu,
  HINSTANCE hInstance,
  LPVOID lpParam
);

这是12个参数(如果将x,y,w和h捆绑为一个矩形,则为9个),还有从类名派生的参数。你将如何减少这种情况?你想把数字减少到更精确的程度吗?

不要让参数的数量困扰你,只要确保它是合乎逻辑的,并有良好的文档记录,让智能感知*帮助你。

*其他编码助手可用!


在我看来,使用长参数列表的理由是数据或上下文本质上是动态的,想想printf();一个使用可变参数的好例子。处理这种情况的一个更好的方法是通过传递一个流或xml结构,这再次减少了参数的数量。

一台机器当然不会介意大量的参数,但是开发人员也会考虑维护开销、单元测试用例和验证检查的数量。设计师也讨厌冗长的参数列表,更多的参数意味着对接口定义的更多更改,无论何时要进行更改。关于耦合/内聚的问题来自以上几个方面。


如果我在一个例程中有7-10个参数,我会考虑将它们捆绑到一个新类中,但如果这个类只是一堆带有getter和setter的字段,那么这个新类必须做一些其他的事情,而不是将值移进和移出。否则,我宁愿忍受很长的参数列表。


众所周知,人们平均一次能记住7 +/- 2件事。我喜欢把这个原则用在参数上。假设程序员都是智商高于平均水平的人,我会说任何10+都太多了。

顺便说一句,如果参数在任何方面相似,我会把它们放在向量或列表中,而不是结构体或类中。


Alan Perlis著名的编程警句之一(在ACM SIGPLAN notice 17(9), 1982年9月中重新叙述)指出:“如果您有一个带有10个参数的过程,那么您可能错过了一些参数。”


非常感谢你的所有回答:

It was a bit surprising to find people who also think (like I do) that 5 parameters is a good limit for the sanity of the code. Generally, people tend to agree that a limit between 3 and 4 is good rule of thumb. This is reasonable as people usually have a bad time counting more than 4 things. As Milan points, on average people can keep more or less 7 things in their head at a time. But I think that you can't forget that, when you are designing/maintaining/studying a routine, you have to keep in mind more things than just the parameters. Some people consider that a routine should have as many arguments as it needs to. I agree, but only for a few specific cases (calls to OS APIs, routines where optimization is important, etc). I suggest to hide the complexity of these routines by adding a layer of abstraction just above these calls whenever possible. Nick has some interesting thoughts on this. If you don't want to read his comments, I summarize for you: in a nutshell, it depends: I hate making hard and fast rules like this because the answer changes not only depending on the size and scope of your project, but I think it changes even down to the module level. Depending on what your method is doing, or what the class is supposed to represent, it's quite possible that 2 arguments is too many and is a symptom of too much coupling. The moral here is don't be afraid of showing your code to your peers, discuss with them and try to "identify areas where you have low cohesion and tight coupling". Finally, I think wnoise much agrees with Nick, and concludes his satirical contribution with this poetical vision (see comments below) of the art of programming: Programming is not engineering. Organization of code is an art because it depends on human factors, which depend too much on context for any hard rule.


我的答案将基于函数被调用的频率。

如果它是一个只被调用一次的init函数,那么就让它占用10个parms或更多,谁在乎呢。

如果它每帧被调用一堆次,那么我倾向于创建一个结构,并只传递一个指针给它,因为这往往更快(假设你不是每次都重建结构)。


根据亚马逊创始人杰夫·贝佐斯的说法,最多只能吃两个披萨:


您应该考虑的一个相关问题是例程的内聚性如何。大量参数可能是一种气味,告诉您例程本身试图做太多事情,因此它的内聚性是可疑的。我同意一个固定的参数数量可能是不可能的,但我猜一个高内聚例程意味着一个低数量的参数。


根据我的说法,可能会有超过4个或某个固定数字的情况。 需要注意的事情可能是

你的方法做的太多了,你需要重构。 您可能需要考虑使用集合或某些数据结构。 重新考虑你的类设计,也许有些东西不需要传递。

从易于使用或易于阅读代码的角度来看,我认为当您需要对方法签名进行“换行”时,应该停下来思考,除非您感到无助,所有使签名更小的努力都没有结果。在过去和现在,一些非常好的图书馆使用超过4-5辆婴儿车。


根据Steve McConnell在Code Complete中的说法,你应该这样做

限制一个程序的数量 参数约为7


我的经验法则是,我需要能够长时间地记住参数,以便查看调用并判断它做了什么。如果我不能看这个方法然后翻到一个方法的调用记住哪个参数是做什么的那就太多了。

对我来说,大约等于5,但我没有那么聪明。你的里程可能会有所不同。

您可以创建一个带有属性的对象来保存参数,并在超出设置的任何限制时将其传入。参见Martin Fowler的《重构》一书和简化方法调用的章节。


I agree with Robert Martin's quote in Clean Code (as cited above): the fewer parameters the better. More than 5-7 parameters and method calls become pretty hard to comprehend. Things get especially bad if some of the parameters are optional (and so take null values), or if all the parameters have the same type (making it even harder to figure out which parameter is which). If you can bundle parameters into cohesive domain objects like Customer and Account, your code will be much more pleasant to work with.

有一个极端的情况:如果你有一个方法调用,它接受一个可变数量的参数,这些参数形成一个逻辑集,有更多的参数会有更少的认知开销。例如,您可能需要一个方法,以重试之间的毫秒数来指定HTTP请求重试次数。可以指定以1s、2s和3s为间隔的三次重试:

retries(1000, 2000, 3000)

在这种有限的情况下,向调用中添加更多参数并不会增加太多的精神负荷。

另一个需要考虑的问题是,您的语言是否支持命名参数列表并允许省略可选参数。较大的已命名参数列表比较大的未命名参数列表更容易理解。

但我还是宁可选择更少的参数,而不是更多的参数。


在最差的5个代码片段中,检查第二个,“这是一个构造函数吗”。它有37⋅4≈150个参数:

下面是一个程序员写的构造函数[…]你们中的一些人可能认为是的,它是一个很大的构造器,但他使用eclipse自动代码生成工具。NOO,在这个构造函数中,我发现了一个小错误,这让我得出结论,这个构造函数是手工编写的。(顺便说一下,这只是构造函数的顶部部分,它不是完整的)。


我要从性能的角度指出的一件事是,根据您向方法传递参数的方式,按值传递大量参数会使程序变慢,因为每个参数都必须被复制,然后放置在堆栈上。

使用单个类来包含所有参数会更好,因为通过引用传递的单个参数将更优雅、更干净、更快!


短期记忆中的七件事?

函数名称 返回函数的值 函数的目的 参数1 参数2 参数3 参数4


97听起来差不多。

少了一点,你就失去了灵活性。