在Java中构造器重载 – 最佳实践

有几个类似的话题,但我找不到一个有足够的答案。

我想知道在Java中构造函数重载的最佳做法是什么。 我对这个问题已经有了自己的想法,但是我想听听更多的build议。

我指的是构造函数重载在一个简单的类和构造函数重载,而inheritance已经重载的类(意味着基类重载构造函数)。

谢谢 :)

虽然没有“官方指导方针”,但我遵循KISS和DRY的原则。 使重载的构造函数尽可能简单,最简单的方法是只调用这个(…)。 这样你只需要检查和处理一次参数。

public class Simple { public Simple() { this(null); } public Simple(Resource r) { this(r, null); } public Simple(Resource r1, Resource r2) { // Guard statements, initialize resources or throw exceptions if // the resources are wrong if (r1 == null) { r1 = new Resource(); } if (r2 == null) { r2 = new Resource(); } // do whatever with resources } } 

从unit testing的angular度来看,可以很容易地testing这个类,因为你可以把资源放入其中。 如果这个class有很多资源(或者一些OO-geeks称之为合作者),请考虑以下两点之一:

做一个参数类

 public class SimpleParams { Resource r1; Resource r2; // Imagine there are setters and getters here but I'm too lazy // to write it out. you can make it the parameter class // "immutable" if you don't have setters and only set the // resources through the SimpleParams constructor } 

Simple中的构造函数只需要拆分SimpleParams参数:

 public Simple(SimpleParams params) { this(params.getR1(), params.getR2()); } 

…或者使SimpleParams成为一个属性:

 public Simple(Resource r1, Resource r2) { this(new SimpleParams(r1, r2)); } public Simple(SimpleParams params) { this.params = params; } 

做一个工厂类

做一个工厂类为你初始化资源,如果初始化资源有点困难,

 public interface ResourceFactory { public Resource createR1(); public Resource createR2(); } 

然后以与参数类相同的方式完成构造函数:

 public Simple(ResourceFactory factory) { this(factory.createR1(), factory.createR2()); } 

把两者结合起来

是的,你可以根据当时对你来说比较容易的方式来混搭两种方式。 参数类和简单的工厂类几乎是相同的事情考虑Simple类,他们使用相同的方式。

我认为最好的做法是通过使用相关的参数默认值调用this()来让重载的构造函数引用单个主构造函数 。 这样做的原因是它使对象的构造状态更为清晰 – 实际上,您可以将主构造函数视为唯一的实际构造函数 ,其他构造函数只是将其委托给它

其中一个例子可能是JTable – 主构造函数接受一个TableModel (加上列和select模型),其他构造函数调用这个主构造函数。

对于超类已经有重载的构造函数的 ,我倾向于认为把父类的构造函数当作主要的构造函数是合理的,并且认为不具有单个主构造函数是完全合法的。 例如,在扩展Exception ,我经常提供3个构造函数,一个只带一个String消息,一个带一个Throwable原因,另一个带两个。 每个构造函数都直接调用super

如果你有一个非常复杂的类,只有一些组合是有效的,你可以考虑使用一个Builder。 在代码方面也很好,但在逻辑上也是如此。

Builder是一个嵌套的类,其方法仅用于设置字段,然后ComplexClass构造函数仅将此Builder作为参数。


编辑:ComplexClass构造函数可以确保Builder中的状态是有效的。 如果你只是在ComplexClass上使用setter,这是很难做到的。

这真的取决于类的types,因为并不是所有的类都是平等的。

作为一般准则,我会build议2个选项:

  • 对于值和不可变类(Exception,Integer,DTO等)使用上面的答案build议的单个主构造函数
  • 对于其他所有的东西(会话bean,服务,可变对象,JPA和JAXB实体等等), 默认的构造函数只能在所有的属性上使用合理的默认值,所以它可以在没有附加configuration的情况下使用