例程可以有参数,这不是新闻.您可以根据需要定义任意数量的参数,但是过多的参数会使您的日常工作难以理解和维护.
当然,您可以使用结构化变量作为解决方法:将所有这些变量放在单个结构中并将其传递给例程.实际上,使用结构简化参数列表是Steve McConnell在Code Complete中描述的技术之一.但正如他所说:
细心的程序员避免捆绑数据,这在逻辑上是必要的.
因此,如果您的例程有太多参数或使用结构来伪装一个大参数列表,那么您可能做错了.也就是说,你没有保持松耦合.
我的问题是,我什么时候可以考虑参数列表太大?我认为超过5个参数,太多了.你怎么看?
尽管第一修正案保证言论自由,但什么时候被认为是如此淫秽以至于可以受到监管?据波特斯图尔特大法官说,"当我看到它时,我就知道了." 这同样适用于此.
我讨厌制定像这样的硬性规则,因为答案的变化不仅取决于项目的规模和范围,而且我认为它甚至会改变到模块级别.根据你的方法正在做什么,或者类应该代表什么,很可能2个参数太多,并且是过多耦合的症状.
我建议通过首先提出问题,并像你一样对你的问题进行鉴定,你真的知道所有这一切.这里最好的解决方案不是依赖于一个快速而快速的数字,而是在同行中寻找设计评论和代码评审,以确定您具有低内聚和紧耦合的区域.
永远不要害怕向同事展示你的工作.如果你害怕,这可能是你的代码出现问题的更大迹象,而且你已经知道了.
如果某些参数是冗余的,则函数只能有太多参数.如果使用了所有参数,则该函数必须具有正确数量的参数.拿这个经常使用的功能:
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个),并且还有从类名派生的参数.你会如何减少这个?你想减少更多的数字吗?
不要让参数的数量打扰你,只要确保它是合乎逻辑的,并且记录良好,让intellisense *帮助你.
*其他编码助手可用!
在清洁法典中,罗伯特C.马丁为这个主题专门写了四页.这是要点:
函数的理想参数数量为零(niladic).接下来是一个(monadic),紧接着是两个(二元).应尽可能避免三个论点(三元论).超过三个(polyadic)需要非常特殊的理由 - 然后不应该使用.
我过去使用的一些代码使用全局变量只是为了避免传递太多参数.
请不要那样做!
(平时).
如果你开始不得不在心理上计算签名中的参数并将它们与调用匹配,那么现在是重构的时候了!
非常感谢您的所有答案:
找到那些也认为(就像我一样)5个参数对代码的健全性有很好限制的人来说有点令人惊讶.
一般来说,人们倾向于同意3到4之间的限制是很好的经验法则.这是合理的,因为人们通常计算超过4件事情的时间不好.
正如米兰指出的那样,平均而言,人们可以一次保持或多或少的7件事情.但我认为你不能忘记,当你设计/维护/研究一个例程时,你必须记住更多的东西,而不仅仅是参数.
有些人认为例程应该有尽可能多的参数.我同意,但仅限于几个特定情况(调用OS API,优化很重要的例程等).我建议尽可能在这些调用之上添加一层抽象来隐藏这些例程的复杂性.
尼克对此有一些有趣的想法.如果您不想阅读他的评论,我总结一下:简而言之,这取决于:
我讨厌制定像这样的硬性规则,因为答案的变化不仅取决于项目的规模和范围,而且我认为它甚至会改变到模块级别.根据你的方法正在做什么,或者类应该代表什么,很可能2个参数太多,并且是过多耦合的症状.
这里的道德是不要害怕向同行展示你的代码,与他们讨论并试图"找出你内聚力低,紧密耦合的区域".
最后,我认为Wnoise非常赞同Nick,并总结了他对编程艺术的这种诗意愿景(见下文评论)的讽刺性贡献:
编程不是工程.代码组织是一门艺术,因为它取决于人为因素,这些因素过于依赖任何硬性规则的背景.
这个答案假设一个OO语言.如果你没有使用它 - 跳过这个答案(换句话说,这不是一个与语言无关的答案.
如果你传递的参数超过3个(特别是内在类型/对象),那不是"太多",而是你可能错过了创建新对象的机会.
查找传递给多个方法的参数组 - 即使传递给两个方法的组几乎保证您应该在那里有一个新对象.
然后,您将功能重构到新对象中,您不会相信它对您的代码和对OO编程的理解有多大帮助.
似乎有其他考虑而不仅仅是数字,这里有一些想到的:
与功能与一次性设置的主要目的的逻辑关系
如果它们只是环境标志,捆绑可以非常方便
Alan Perlis着名的编程语言之一(在ACM SIGPLAN Notices 17(9),1982年9月中叙述)指出"如果你有一个包含10个参数的程序,你可能会错过一些."
根据Code Complete中的 Steve McConnell ,您应该这样做
将例程参数的数量限制为大约7
对我来说,当列表在我的IDE上越过一行时,它的一个参数太多了.我希望在一行中看到所有参数而不会破坏目光接触.但这只是我个人的偏好.
我普遍同意5,但是,如果我需要更多的情况,这是解决问题的最明确的方法,那么我会使用更多.
短期记忆中的七件事?
功能名称
函数的返回值
功能的目的
参数1
参数2
参数3
参数4
在Worst 5 Code Snippets中,检查第二个,"这是一个构造函数".它有超过37⋅4≈150参数:
在这里,程序员编写了这个构造函数[...]你可能认为它是一个很大的构造函数,但是他使用了eclipse自动代码生成工具[.] NOO,在这个构造函数中有一个我发现的小bug,这让我得出结论,这个构造函数是手工编写的.(顺便说一句,这只是构造函数的顶部,它不完整).
一个不必要的.我并不是说要搞笑,但有一些功能必然需要很多选择.例如:
void * mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t offset);
共有6个论点,每个论点都是必不可少的.此外,它们之间没有共同的联系来证明捆绑它们的合理性.也许你可以定义"struct mmapargs",但这会更糟.
根据Perl Best Practices,3可以,4太多了.这只是一个指导方针,但在我们的商店里,这是我们努力坚持的.
我自己在5个参数中绘制了公共函数的限制.
恕我直言,长参数列表仅在私有/本地助手函数中可接受,这些函数仅用于从代码中的几个特定位置调用.在这些情况下,您可能需要传递大量的状态信息,但可读性并不是一个大问题,因为只有您(或将维护您的代码并且应该了解模块基础知识的人)必须关心调用那个函数.
您应该考虑的一个相关问题是例行公事的凝聚力.大量的参数可能是一种气味,告诉你例程本身正在试图做太多,因此它的凝聚力是可疑的.我同意很难和快速数量的参数可能是不可能的,但我猜想高内聚程序会意味着参数数量很少.
97听起来恰到好处.
任何更少,你失去灵活性.