可选参数是否有用或阻碍了应用程序维护?[关闭]


15

如标题所述,可选参数(例如C#中使用的那些参数)是否有用,还是对应用程序维护的障碍,应避免使用,因为它们会使代码更难于理解?


3
免责声明:滥用任何语言功能都可能被滥用。如果一种语言以一种聪明的方式实现了该功能,并且该语言功能与现有语言功能没有太多重叠,那么它们就很好了,实际上非常有用。Python具有一些整齐的参数打包/解压缩和其他参数“技巧”(技巧很好,不是Perl的意思)。
工作

尝试在不使用可选参数的情况下用C#编写与Excel交互的应用程序。那应该毫无疑问地回答您的问题。
Dunk

Answers:


22

以我的经验,可选参数是一件好事。我从来没有发现它们令人困惑(至少没有比实际功能更令人困惑),因为我总是可以得到默认值并知道正在调用什么。

它们的一种用途是当我必须向已经普遍使用的功能或至少在公共接口中添加另一个参数时。没有它们,我将不得不重做原始函数以调用具有另一个参数的函数,如果我多次添加参数,则该函数可能会变得很老。


1
+1并且这对于重载方法很有价值,该方法添加了诸如new Circle(size, color, filled, ellipseProportions)where sizecolorrequired之类的参数,其余为默认值。
Michael K 2010年

15

通常,如果您经常需要许多/可选参数,则您的函数做得太多,应该分解。您可能会违反SRP(单一责任原则)。

查找可以分组的参数,例如(x和y,成为一个点)。

这些可选参数标志是否带有默认值?如果使用标志,则应拆分该函数。

这并不是说您不应该具有可选参数,但是通常,一个或两个以上的参数会提示代码有异味。

也可能是该函数实际上应该是一个类,并且可选参数已更改为属性,而必需参数是构造函数的一部分,这可能是一个线索。


1
+1表示谨慎。任何功能,无论多么出色,都可能被滥用。
Michael K

3
对于生成过度设计的馄饨代码,这是一个很好的建议,其中API的用户必须至少使用6个类和15个函数才能使最简单的事情发生。
dsimcha

1
@dsimcha,你怎么从我写的书中得到?哇。请解释?这对于拥有“超级功能”的设计同样是糟糕的,这是当您具有许多可选参数时所得到的。阅读有关SOLID设计原则的信息,并编写可测试的代码。最好使用TDD。然后返回并尝试向我解释,减少函数中的参数是一件坏事。
CaffGeek

1
可测试的代码很不错,但是干净,可用的API也不是太细粒度或冗长,并且不会在函数是适当抽象的情况下简化类。我相信单一责任原则,并在较高的抽象级别上定义职责。如果将职责定义的级别过低,那么各个单元将变得过于简单,以至于它们之间的交互过于复杂。
dsimcha 2010年

1
@dsimcha,您错过了重点。单个单位应保持为单个单位,而不应将其合并为一个功能。这也不意味着它们都是公开可用的功能。API是代码的门户,并且应该简洁明了。具有多个可选参数的函数既不简洁也不简洁。但是,使用逻辑参数重载单个函数要清楚得多。例如,许多API中都有一些函数,其中两个参数是可选的,但一个或另一个是必需的。当两者都标记为可选时,这清楚吗?
CaffGeek

4

可选参数很好

通常,理由是:a)您知道自己的方法有很多可能的参数,但又不想因担心API混乱而不想重载,或者b)当您不知道所有可能的参数但您却想不想强迫您的用户提供数组。在每种情况下,可选参数都以简洁,优雅的方式出现。

这里有些例子:

1.您要避免重载并且不想指定数组

看一下C,Perl,Java等中的printf()。这是可选参数功能强大的一个很好的例子。

例如:

printf("I want %d %s %s",1,"chocolate","biccies");

printf("I want %d banana",1);

没有重载,没有数组,简单而直观(一旦您掌握了标准的字符串格式代码)。某些IDE甚至会告诉您格式字符串是否与可选参数不匹配。

2.您想允许使用默认值,并将默认值对方法用户隐藏

sendEmail(“ test@example.org”);

sendEmail方法检测到缺少各种基本值,并使用定义的默认值(主题,正文,cc,bcc等)将其填充。API保持干净,但灵活。

有关太多参数的注释

但是,正如其他人所述,方法的强制参数过多表示您的设计可能有问题。如果它们共享相同的类型,则尤其如此,因为开发人员可能会偶然切换它们,从而在运行时导致奇怪的结果:

String myMethod(String x, String y, String z, String a, int b, String c, int d) {}

引入参数对象重构以创建的理想选择

String myMethod(ParameterObject po) {}

class ParameterObject {
  // Left as public for clarity
  public String x;
  public String y;
  ... etc

}

反过来,这可以基于带有提供的规范作为参数对象的Factory模式进行更好的设计。


1
诸如printf之类的字符串格式化函数是该规则的例外,有人可能会争辩说,尽管它们使用了无限制的可选参数列表,但尽管实现方式不同,但它更像参数是数组而不是可选参数。
CaffGeek

@Chad我已经调整了答案,以更好地区分可选参数以及它们何时转变为代码气味(如您在答案中所述)。
加里·罗

@Gary Rowe,在大多数情况下,太多可选参数也是不好的。
CaffGeek

@Chad我同意,但是大多数语言都没有提供一种方法来指定可选参数的数量限制,所以这是一种全有或全无的方法。您被迫将其留给方法来强制执行,并且显然,如果您的方法要处理500个变量,则肯定需要对其进行重构。
加里·罗

@Gary Rowe,您的意思是“大多数语言都没有提供一种方法来限制可选参数的数量”?在大多数语言中,您都将它们标记为此类,或者在调用函数时不提供它们的值,但是函数头仍然定义了参数。当然,在某些语言中,您可以在填写定义的参数后添加任意数量的参数,但是我认为这不是我们在这里谈论的可选参数。(除了字串格式例外)
CaffGeek 2010年

2

C#中默认参数的问题之一(我认为void DoSomething(int x = 1))是它们是常量。这意味着,如果更改默认值,则必须重新编译该方法调用的所有使用者。尽管这样做很容易,但是在某些情况下这很危险。


1

这取决于您的代码在做什么。如果存在合理的默认值,则应使用可选参数,但如果没有合理的默认值,则添加可选参数会使代码更复杂。在许多情况下,可选参数是绕过零检查和清除分支逻辑的一种巧妙方法。Javascript没有可选参数,但是可以使用||来模拟它们。(逻辑或),并且在进行与数据库相关的工作时会一直使用它,因为如果用户未提供某些值,那么我将在||的帮助下替换自己的值。这省去了编写一堆if语句的麻烦。


1

可选参数是一种使简单事物同时变得简单和复杂事物同时实现的好方法。如果至少在快速和肮脏的用例中,大多数用户都希望有一个明确的合理默认值,则他们不必每次调用函数时都必须编写样板来手动指定它。另一方面,如果人们可能有充分的理由要更改它,则需要对其进行公开。

恕我直言,使用班级是一个糟糕的解决方案,因为它冗长,效率低下并且与班级行为的典型心理模型不一致。函数是动词的完美抽象,即做某事然后返回。类是名词的正确抽象,即具有状态并且可以通过多种方式进行操作的事物。如果前者应该是API用户的思维模式,则不要使其成为类。


1

可选参数的问题在于,人们倾向于将越来越多的参数添加到函数中,而不是将相关代码提取到新函数中。这在php中达到了极致。例如:

bool array_multisort ( array &$arr [, mixed $arg = SORT_ASC
                      [, mixed $arg = SORT_REGULAR [, mixed $... ]]] )

1

可选参数基本上是重载函数的另一种方式。因此,这基本上可以归结为:“重载函数是否不好”?


1

我最初很喜欢python中的此功能,并用它来“扩展”已经使用的方法。它看起来不错,很容易,但是很快就回来了。因为当我添加一个可选参数时,这是在修改旧客户端所依赖的现有方法的行为,并且这种方式不会被现有的单元测试用例捕获。基本上,这样做违反了开放封闭原则。代码是可扩展的,但已关闭以进行修改。因此,我相信使用此功能修改现有代码不是一个好主意。但是如果从一开始就可以使用


0

我认为重载具有不同签名(即参数)的函数比使用可选参数更好。


为什么?我认为它更清洁的,如果你能一堆重载方法使用默认PARAMS如果所有方法都具有相同的基本功能组合成一个方法
阿米特·瓦德华

您可以认为。我不是认为Microsoft会以正确的方式做所有事情的人,但是,如果您是正确的话,那么在使用.NET框架时,我永远不会看到重载,只是一个巨大的函数签名-就像在VB6中一样。
HardCode 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.