有时候(很少),创建一个需要大量参数的函数似乎是最好的方法。但是,当我这样做时,我觉得我经常随机选择参数的顺序。我通常按照“重要性顺序”进行操作,首先要考虑最重要的参数。
有一个更好的方法吗?是否有一种“最佳做法”的参数排序方式可以提高清晰度?
有时候(很少),创建一个需要大量参数的函数似乎是最好的方法。但是,当我这样做时,我觉得我经常随机选择参数的顺序。我通常按照“重要性顺序”进行操作,首先要考虑最重要的参数。
有一个更好的方法吗?是否有一种“最佳做法”的参数排序方式可以提高清晰度?
Answers:
通常:使用它。
为您的功能编写一个测试,一个真实的测试。
东西你实际上喜欢做的事与该功能。
看看您按什么顺序放下了它们。
除非您已经拥有(或知道)一些功能类似的功能。
在这种情况下:至少在第一个论点上,遵循他们已经做的事情。
例如,他们是否都将文档/对象/文件指针/值系列/坐标作为第一个参数?看在上帝的份上,顺应那些论点。
避免混淆您的同事和您未来的自我。
我通常会遵循这些规则,尽管并不总是具有相同的优先级。我想这是一个自动的思考过程,除了公共API设计之外,我并没有考虑太多。
尤其是在OOP中,请根据参数对操作或消息的语义重要性来选择参数。参数名称良好的方法的签名应:
(由于这些原因,有时使用自定义类型或别名而不是基元可能会增加签名的表现力。)
最“重要”的参数排在第一位(或下一个...)
频率也很重要,尤其是在您没有命名参数但可以在位置参数上具有默认值的语言中。这意味着参数的顺序没有变化,并且很明显,如果您想强制使用第N个参数的默认值,则无法设置N + 1个参数(除非您的语言具有占位符参数的概念, )。
对您来说,好消息是,频率通常与重要性相关,因此与上一点紧密相关。然后,可能要由您自己设计API以使其具有适当的语义。
如果您的方法/函数接受一些输入并产生一个输出,而该输出不被“返回”(通过return语句)或“抛出”(使用异常系统),则您可以选择传递使用您的其他参数(或输入参数)将值返回给调用方。这与语义有关,在大多数情况下,让第一个参数定义输出,而最后一个参数接收输出将是有意义的。
另外,具有较少参数并最大化语义的另一种方法是使用功能性方法或定义Builder模式,以便您可以清楚地堆叠输入,定义输出并在需要时检索它们。
(注意,我没有提到全局变量,因为为什么要使用一个,对吗?)
易用性
如果您遵循ZJR的建议,上面的大多数内容将很自然地显示出来:使用它!
考虑重构
如果您担心参数排序,则可能是在上面以及您的API设计错误的事实中找到了它的根源。如果参数太多,则很可能会对某些内容进行组件化/模块化和重构。
考虑性能
请记住,使用参数时,某些语言的实现会对运行时内存管理产生非常重要的影响。因此,许多语言的样式手册建议保持参数列表简洁明了的原因。以最大4个参数为例。我将其作为练习让您找出原因。
Bevan的回答和对Clean Code的建议的提及也同样重要!
我谨此提出,担心参数排序是担心错误的事情。
在鲍勃叔叔的书《干净的代码》中,他有说服力地主张,方法决不能有两个以上的参数-大多数应该只有一个参数(如果有的话)。在这种情况下,排序是显而易见的或不重要的。
无论多么不完美,我都在尝试遵循Bob叔叔的建议-它正在改进我的代码。
在一种罕见的方法似乎需要更多信息的情况下,引入参数对象是一个好主意。通常,我发现这是发现对我的算法至关重要的新概念(对象)的第一步。
我尝试将IN参数放在第一位,将OUT参数放在第二位。也有一些自然顺序,例如createPoint(double x, double y)
,强烈推荐使用createPoint(double y, double x)
。
addAllTo(target, something1, something2)
。
我从未见过关于此特定主题的文档化“最佳实践”,但是我的个人标准是按照它们在所使用的方法中出现的顺序列出它们,或者如果该方法更多是在传递给数据层时,我将按照它们在db模式或数据层方法中出现的顺序列出它们。
另外,当一个方法有多个重载时,我注意到典型的方式是从所有(或大多数)方法共有的参数开始列出它们,并在每个方法重载的末尾附加每个不同的方法,例如:
void func1(string param) { }
void func2(string param, int param2) { }
void func3(string param, string param3) { }
void func3(string param, int param2, string param3) { }
我经常遵循C / C ++惯例,即const
首先放置参数(即,按值传递的参数),然后是按引用传递的参数。这不一定是调用函数的正确方法,但是,如果您对每个编译器如何处理参数感兴趣,请查看以下链接,以了解控制规则和/或将参数压入堆栈的顺序。
http://msdn.microsoft.com/zh-CN/library/zthk2dkh%28v=vs.80%29.aspx
有时候(很少),创建一个需要大量参数的函数似乎是最好的方法。
使用多个参数通常可以清楚地表明,您违反了此方法中的SRP。需要许多参数的方法不可能只做一件事。执行可能是数学函数或配置方法,实际上确实需要几个参数。我会避免使用多个参数,因为魔鬼会避开圣水。方法中使用的参数越多,该方法(过于)复杂的机会就越大;越复杂意味着:难以维护,就越不可取。
但是,当我这样做时,我觉得我经常随机选择参数的顺序。我通常按照“重要性顺序”进行操作,首先要考虑最重要的参数。
在priniple中,您是随机选择的。当然,您可能会认为参数A比参数B更相关;但对于您的API用户而言却并非如此,他们认为B是最相关的参数。因此,即使您专注于选择顺序-对于其他人,它似乎也是随机的。
有一个更好的方法吗?是否有一种“最佳做法”的参数排序方式可以提高清晰度?
有几种解决方法:
a)普通情况:不要使用多个参数。
b)如您未指定的那样,选择了哪种语言,就有可能选择了带有命名参数的语言。这是一个不错的语法糖,它使您可以放宽参数的排序的意义:fn(name:"John Doe", age:36)
并非每种语言都允许如此精美。那又如何呢?
c)您可以使用Dictionary / Hashmap / Associative Array作为参数:例如,Javascript将允许以下操作:fn({"name":"John Doe", age:36})
与(b)相距不远。
d)当然,如果您使用的是Java之类的静态类型语言。您可以使用Hashmap,但是HashMap<String, Object>
当参数具有不同的类型(并且需要强制转换)时,您会丢失类型信息(例如,使用时)。
下一步的逻辑步骤是传递一个Object
具有适当属性的(如果使用Java的话)或更轻巧的结构(例如编写C#或C / C ++)。
经验法则:
1)最佳情况-您的方法根本不需要任何参数
2)好的情况-您的方法需要一个参数
3)可容忍的情况-您的方法需要两个参数
4)所有其他情况应重构
与@Wyatt Barnetts的答案类似,除了该方法的一些参数或非常明确的参数外,我建议改为传递一个对象。这通常更易于更新/维护,更清晰易读,并且消除了担心订购的必要性。同样,方法的太多参数是代码的味道,您可以遵循一些常见的重构模式来帮助纠正它。
明确的例子:
public int add(int left, int right)
{
return left + right;
}
由于这是一个非常明确定义的示例,并且加法是可交换的(顺序无关紧要),所以就随它去吧。
但是,如果添加一些更复杂的内容:
public SomeComplexReturnValue Calculate(int i, float f, string s, object o)
{
// do work here
}
会成为:
public class SomeComplexInputForCalculation
{
public int i;
public float f;
public string s;
public object o;
}
public SomeComplexReturnValue Calculate(SomeComplexInputForCalculation input)
{
// do work here
}
希望这可以帮助...
“重要至上”并不意味着很多。有一些约定。
如果您传递了调用对象(通常称为发送者),则该方法优先。
列表应该有一定的流利性,这意味着您在阅读时应该知道参数的含义。例:
CopyFolder(字符串路径,bool递归);
如果将递归放在首位,那会造成混乱,因为还没有上下文。如果现在已经要复制(1),文件夹(2),则递归参数就变得有意义了。
这也使类似IntelliSense的功能可以很好地发挥作用:用户在填写自变量时会学习,他会逐渐了解该方法及其作用。同样,对于相等的零件,过载应保持相同的顺序。
然后,您可能仍然会发现在这方面存在“相等”的参数,并且您可能会想让顺序取决于参数的类型。仅仅因为连续有几个字符串然后有几个布尔值看起来更好。在某种程度上,这将成为一种艺术而不是一种技能。
我不太关心您应该将所有参数都包装到一个对象中以仅仅得到一个参数的说法。那只是在自欺欺人(它不会使方法变得更简单,它仍然具有所有这些参数,您只是将它们隐藏了)。如果将方法之间的设置传递几次,这可能仍然很方便,重构肯定会变得容易得多,但是在设计方面,这只是假装您有所作为。最终您将不会得到一个有意义的对象来表示某些东西,它只是一堆参数,与方法声明中的列表没有什么不同。这不会使鲍伯叔叔高兴。
MessageBox.Show
。还要研究一下。