构造函数的参数数量

35

我有一个类,需要在构造函数中传递12个参数,因此我认为这个类的设计存在问题。

我想问一下,是否有任何设计模式或关于类设计,特别是构造函数的一般规则的集合。


看一下这个问题:一个构造函数应该有多少个变量。虽然 OP 使用的是 C#,但答案也适用于 C++。 - Tony
2
一个拥有12个参数的构造函数是代码异味。很可能,你的类试图做太多事情了。 - John Dibling
5个回答

38

对我来说,12个参数绝对听起来太多了。减少参数的选项如下:

  1. 引入参数对象,将逻辑相关的参数分组到一个对象中,然后传递该对象而不是单独的参数。

  2. 引入构建器模式(可选使用方法链)。这并没有减少实际的参数列表,但它使得代码更易读,特别是如果您有几个不同的创建场景需要使用不同的参数。所以,不再是:

    MyClass someObject = new MyClass(aFoo, aBar, aBlah, aBaz, aBorp, aFlirp, 
            andAGoo);
    MyClass anotherObject = new MyClass(aFoo, null, null, aBaz, null, null, 
            andAGoo);
    

    你可以拥有

    MyClass someObject = new MyClassBuilder().withFoo(aFoo).withBar(aBar)
            .withBlah(aBlah).withBaz(aBaz).withBorp(aBorp).withFlirp(aFlirp)
            .withGoo(aGoo).build();
    MyClass anotherObject = new MyClassBuilder().withFoo(aFoo).withBaz(aBaz)
            .withGoo(aGoo).build();
    
  3. (也许我应该从这里开始;-) 分析参数 - 是否所有参数都真的需要在构造函数中(即强制性)? 如果一个参数是可选的,您可以通过其常规setter而不是构造函数来设置它。


5
在尝试1或2之前,我肯定会先做3 :) - Matthieu M.

10

如果你的函数有十一个参数,那么你可能忘记了一个或更多

我喜欢这句话,因为它概括了一切:糟糕的设计导致了糟糕的设计。

我从Herb Sutter和Andrei Alexandrescu的书《C++编码规范:101条规则、指南和最佳实践》中引用了这句话。

编辑:直接引用的是如果你有一个带有十个参数的过程,那么你可能错过了一些。它本身是来自Alan Perlis的名言

具有如此多参数的函数是糟糕设计的一个症状。 其中一种可能性是尝试将部分参数封装在具有定义目标的实体/类中(而不是列出所有没有有意义结构的参数的垃圾类)。


永远不要忘记单一责任原则 因此,类的大小保持有限,因此成员参数的数量也保持有限,从而限制其构造函数所需的参数大小。如下面的评论之一所说,带有如此多构造函数参数的类可能处理太多与其主要目标无关的琐碎细节。


建议查看这个: 有太多参数是多少?


2
+1 这是代码异味。听起来这个类负责太多细节了。但我认为参数类只是掩盖了这种气味。 - daramarak
1
我查了这本书,确实有这句话。直接引用是“如果你有一个有十个参数的过程,那么你可能错过了一些东西”。它本身是出自Alan Perlis的名言。 - wardw
@wardw 很好。我已经在答案中包含了正确的引用。 - Stephane Rolland

6

12个参数,设计上很可能有问题。

这些参数是用来做什么的?

  • 这个类只是将它们发送到其他构造函数中吗? 那么也许它应该接受已准备好的对象的接口。
  • 这个类很大,并且对所有这些参数进行了很多操作吗? 那么这个类就承担了太多责任,应该接受负责处理细节的类。
  • 这些参数中是否存在“聚集”? 也许其中一些参数是创建中的类。将它们封装起来并赋予适当的责任。

另一种情况是这些参数用于低级别、性能关键的构造,此时设计只需退居次要地位,但这种情况很少发生。


4
如果可能的话,您可以按类别分组参数并将它们的实例传递给构造函数。

这是Win32 API函数采用的方法。 - Alexandre C.

2

我认为在使用状态模式时,这种做法是可以接受的。然而,我想建议在可能情况下传递生成参数的对象,然后在构造函数中从该对象加载数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接