有多less个参数太多?
例程可以有参数,这不是新闻。 您可以根据自己的需要定义许多参数,但其中的许多参数会使您的日常难以理解和维护。
当然,你可以使用结构化variables作为解决方法:将所有这些variables放在一个结构体中,并将其传递给例程。 事实上,使用结构来简化参数列表是Steve McConnell在Code Complete中描述的技术之一。 但正如他所说:
细心的程序员避免将数据捆绑在逻辑上是必要的。
所以,如果你的例程有太多的参数,或者你使用一个结构来伪装一个大的参数列表,你可能做错了什么。 也就是说,你没有保持连接松散。
我的问题是, 我什么时候可以考虑参数列表太大? 我觉得超过5个参数太多了。 你怎么看?
什么时候被认为是如此淫秽,以至于即使第一修正案保证言论自由,也可以被pipe制。 根据Potter Stewart法官的说法,“当我看到它的时候,我就知道了。 这里也是一样。
我讨厌制定这样严格而快速的规则,因为答案不仅取决于项目的大小和范围,而且我认为它甚至会改变到模块级别。 根据你的方法在做什么,或者类应该表示什么,很可能2个参数太多,是一个过多耦合的症状。
我会build议通过首先提出这个问题,并且像你那样限定你的问题,你确实知道所有这些。 这里最好的解决scheme不是依靠一个硬性和快速的数字,而是在同行之间寻找devise审查和代码审查,以确定你的凝聚力低和紧密耦合的领域。
不要害怕向同事展示你的工作。 如果你害怕,这可能是你的代码出了问题的更大的信号,而且你已经知道了 。
如果某些参数是冗余的,则函数只能有太多的参数。 如果使用所有参数,则该function必须具有正确数量的参数。 拿这个常用function:
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),并且还有从类名称派生的参数。 你怎么减less这个? 你想减less更多的点数?
不要让参数的数量打扰你,只要确保它是逻辑和有据可查,让智能感知*帮助你。
*其他编码助手可用!
在“ 清廉法典”中 ,罗伯特·C·马丁(Robert C. Martin)专门写了四页。 要点是:
一个函数的理想参数个数是零(niladic)。 接下来是一个(monadic),其次是两个(二元)。 应尽可能避免三个论点(三元)。 超过三个(多边形)需要非常特殊的理由 – 然后不应该使用。
我曾经使用的一些代码使用全局variables只是为了避免传递太多的参数。
请不要这样做!
(平时)。
如果你开始不得不精神统计签名中的参数并将它们与呼叫进行匹配,那么现在是重构的时候了!
非常感谢您的答复:
-
find那些也认为(和我一样)认为5个参数对于代码的完整性来说是一个好的限制的人是有点令人惊讶的。
-
一般来说,人们倾向于认同3到4之间的限制是很好的经验法则。 这是合理的,因为人们通常有不好的时间计数超过4件事情。
-
正如米兰所指出的那样 ,平均来说,人们一次可以保持7种或多或less的东西。 但是我认为你不能忘记,当你devise/维护/学习一个例程时,你必须记住更多的东西,而不仅仅是参数。
-
有些人认为,一个例程应该有它所需要的尽可能多的参数。 我同意,但仅限于一些特定情况(调用OS API,优化非常重要的例程等)。 我build议隐藏这些例程的复杂性,只要有可能就在这些调用之上添加一层抽象。
-
尼克在这方面有一些有趣的想法 。 如果你不想看他的评论,我总结一下:简而言之, 这取决于 :
我讨厌制定这样严格而快速的规则,因为答案不仅取决于项目的大小和范围,而且我认为它甚至会改变到模块级别。 根据你的方法在做什么,或者类应该表示什么,很可能2个参数太多,是一个过多耦合的症状。
这里的道德是不要害怕向同行展示你的代码,与他们讨论,并试图“确定你有低凝聚力和紧密耦合的领域” 。
-
最后,我认为wnoise与Nick很一致,并且总结了他对编程艺术的这种诗意的憧憬 (见下面的评论)的讽刺性贡献:
编程不是工程。 代码的组织是一门艺术,因为它取决于人为因素,过分依赖任何硬性规则的背景。
这个答案假设一个OO语言。 如果你不使用一个 – 跳过这个答案(换句话说,这不是一个语言不可知的答案。
如果你传递了3个以上的参数(特别是内部types/对象),这并不是说“太多”,而是你可能错过了创build一个新对象的机会。
寻找传入多个方法的参数组 – 甚至一个组传递到两个方法几乎保证你应该有一个新的对象。
然后你将function重构到新的对象中,你不会相信它对代码和对OO编程的理解有多大的帮助。
似乎还有其他的考虑,而不仅仅是数字,这里有一些想到:
-
逻辑关系的function与一次性设置的主要目的
-
如果他们只是环境标志,捆绑可以非常方便
Alan Perlis的着名编程警句之一(在1982年9月的ACM SIGPLAN公告17(9)中叙述)指出:“如果你有一个有10个参数的程序,那么你可能错过了一些。
根据代码完成史蒂夫McConnell,你应该
将例程参数的数量限制在七个左右
对于我来说,当我的IDE中的列表跨越一行,那么这个参数太多了。 我希望在一行中看到所有参数而不会造成眼神接触。 但这只是我个人的偏好。
我一般都同意5,但是,如果有一种情况我需要更多,而且是解决问题的最明确的方法,那我就用更多。
短期记忆有七件事?
- 函数的名称
- 函数的返回值
- function的目的
- 参数1
- 参数2
- 参数3
- 参数4
在最差的5个代码片段中 ,检查第二个“这是一个构造函数”。 它有超过37⋅4≈150参数:
在这里,一个程序员写了这个构造函数[…]你可能会认为是一个很大的构造函数,但是他使用了eclipse自动代码生成工具[。] NOO,在这个构造函数中有一个小错误,得出这个构造函数是手写的。 (顺便说一下,这只是构造函数的顶部,不完整)。
多一个必要的。 我并不是说要滑稽,但是有一些function需要相当多的select。 例如:
void * mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t offset);
有6个论点,每一个都是必不可less的。 此外,他们之间没有共同的联系来certificate捆绑。 也许你可以定义“struct mmapargs”,但那会更糟。
我会自己为5个参数绘制公共函数的限制。
恕我直言,长参数列表只能在私人/本地帮助器function,只能从代码中的几个特定的地方调用。 在这种情况下,您可能需要传递大量的状态信息,但可读性并不是一个大问题,因为只有您(或将维护您的代码并应该理解模块基本原理的人)必须关心调用该函数。
你应该考虑的一个相关问题是例程的凝聚力 。 大量的参数可能是一种嗅觉,告诉你这个例程本身试图做太多的事情,因此它的凝聚力是可疑的。 我同意,参数的硬性和快速的数量可能是不可能的,但我猜测一个高度的凝聚程序意味着参数的数量很less。
97听起来是正确的。
less了,你就失去了灵活性。
根据Perl最佳实践 ,3是好的,4是太多了。 这只是一个指导,但在我们的商店,这是我们试图坚持。
作为一般的经验法则,我停在三个参数。 还有,现在是时候传递一个参数数组或一个configuration对象,这也允许在不改变API的情况下添加未来的参数。
参数列表的长度限制只是一个限制。 而限制意味着施加暴力。 这听起来很有趣,但即使在编程时也可以是非暴力的。 只要让代码规定的规则。 很显然,如果你有很多参数,那么函数/类方法的主体将会足够大以利用它们。 大的代码片段通常可以被重构并分成更小的块。 所以你得到的解决scheme有许多参数作为免费的奖金,因为它们被分成了较小的重构代码段。
我从性能angular度指出的一点是,根据如何传递参数给方法,按值传递大量参数会减慢程序的速度,因为每个参数都必须被复制,然后放在堆栈上。
使用单个类来包含所有参数会更好,因为通过引用传递的单个参数将更加优雅,更清晰,更快!
根据我的情况,可能会出现超过4个或固定数量的情况。 要注意的事情可能是
- 你的方法做得太多了,你需要重构。
- 你可能要考虑使用一个集合或一些数据结构。
- 重新思考你的class级devise,也许有些事情不需要传递。
从易用性或易读性的angular度来看,我认为当你需要有一个“文字包装”的方法签名时,应该让你停下来思考,除非你感到无助,而且使得签名更小的所有努力导致没有结果。 过去和现在的一些非常好的图书馆使用4-5个以上的图书馆。
我的经验法则是,我需要能够记住参数足够长的时间来查看一个调用,并告诉它做了什么。 所以,如果我不能看方法,然后翻转到一个方法的调用,并记住哪个参数做什么,那么有太多。
对我来说,相当于5,但我不是那么明亮。 你的旅费可能会改变。
您可以创build一个具有属性的对象来保存参数,如果超过了设置的限制,就将其传入。 请参阅Martin Fowler的“ 重构”一书以及关于简化方法调用的章节。
这很大程度上取决于你正在工作的环境。例如javascript。 在JavaScript中,传递参数的最好方法是使用带有键/值对的对象,这在实践中意味着您只有一个参数。 在其他系统中,最佳位置将是三四个。
最后,这一切归结为个人的品味。
我会同意3是好的,4是太多了作为一个准则。 有了更多的3个参数,你不可避免地做了多一个任务。 更多的是一个任务应该被分解成单独的方法。
但是,如果我查看了我所研究的最新项目,那么例外情况就会比比皆是,而且大多数情况下很难得到3个参数。
如果我在一个例程中有7-10个参数,我会把它们绑定到一个新的类中, 但是如果这个类只是一堆带有getter和setter的字段,那么这个类就不行了。出。 否则,我宁愿忍受长参数列表。
这是一个众所周知的事实,平均来说,人们可以一次保持7 +/- 2的东西。 我喜欢用参数的原理。 假设程序员都是高于平均水平的人,我会说10+以上的东西太多了。
顺便说一句,如果参数是相似的,我会把他们在一个向量或列表,而不是一个结构或类。
我会根据我的答案调用函数的频率。
如果它是一个只被调用一次的init函数,那么让它花费10个或更多,谁在乎。
如果它被称为每帧一堆,那么我倾向于做一个结构,只是传递一个指针,因为这往往会更快(假设你不是每次重build结构)。
根据亚马逊名气的杰夫·贝索斯(Jeff Bezos)的说法,最多只能吃两种比萨饼 :