Constructor overloading in Java - best practice

有一些类似的话题,但我找不到一个充分的答案。

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

I'm referring to both constructor overloading in a simple class and constructor overloading while inheriting an already overloaded class (meaning the base class has overloaded constructors).

谢谢:)

182922 次浏览

我认为最佳实践是使用重载构造函数引用的 单主构造函数单主构造函数,方法是使用相关参数缺省值调用 this()。这样做的原因是,它使得对象的 构造状态是什么变得更加清晰——实际上,你可以把主构造函数想象成 只有真正的构造函数,其他构造函数只是委托给它

这方面的一个例子可能是 JTable-主构造函数采用 TableModel(加上列和选择模型) ,其他构造函数称这个主构造函数。

对于子类 超类已经有重载的构造函数,我倾向于假设将父类的任何构造函数视为 初选是合理的,并且认为没有单个主构造函数是完全合法的。例如,在扩展 Exception时,我通常提供3个构造函数,一个只接受 String消息,一个接受 Throwable原因,另一个两者都接受。每个构造函数都直接调用 super

如果您有一个非常复杂的类,其中有很多选项,只有一些组合是有效的,那么可以考虑使用 Builder。在代码方面和逻辑方面都很好。

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


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

It really depends on the kind of classes as not all classes are created equal.

作为一般准则,我建议两种选择:

  • 对于 价值 & 不可变类(例外、整数、 DTO 等) ,按照上面的回答建议使用 单主构造函数单主构造函数
  • 对于其他所有东西(会话 bean、服务、可变对象、 JPA 和 JAXB 实体等等) ,使用 default constructor only,在所有属性上使用合理的默认值,这样就可以在不进行额外配置的情况下使用它

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

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
}


}

从单元测试的角度来看,测试该类将变得很容易,因为您可以将资源放入其中。如果类有许多资源(或者像一些 OO 极客所说的合作者) ,请考虑以下两件事情之一:

创建一个参数类

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类的方式相同,参数类和简单工厂类几乎是相同的。

构造函数重载类似于方法重载。可以通过重载构造函数来以不同的方式创建对象。

编译器根据构造函数中存在的参数数量和其他参数(如参数传递的顺序)来区分构造函数。

有关 java 构造函数的详细信息,请访问 https://tecloger.com/constructor-in-java/