有一些类似的主题,但我找不到一个有足够答案的主题。
我想知道在Java中构造函数重载的最佳实践是什么。 我已经对这个问题有了自己的想法,但我想听听更多建议。
我指的是简单类中的构造函数重载和构造函数重载,同时继承已经重载的类(意味着基类具有重载的构造函数)。
谢谢 :)
虽然没有"官方指南",但我遵循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
}
}
从单元测试的角度来看,测试类很容易,因为你可以将资源放入其中。如果该类有许多资源(或者像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类它们以相同的方式使用,参数类和简单的工厂类几乎是一样的。
+1非常好的帖子
我已经在这个以及其他示例中注意到构造函数定义的编写顺序在构造函数调用中使用最少的参数。这是标准的Java风格吗?为什么?:在我看来,这样做是有意义的,就像你应该看到的第一个构造函数定义那样具有所有细节的那个。
@JosieThompson据我所知,这在任何标准中都没有定义。我同意首先使用完整的构造函数可以快速查看所有方法参数;但是,通过参数计数对它们进行排序,可以让您按照页面上的重载调用进行操作,当您考虑我们如何读写代码时,这些调用会感觉更自然。
有多个构造函数可以在每个构造函数上有1个不同类型的参数吗?喜欢 - new Object(int aa)/ new Objec(String bb)?
我认为最佳实践是通过使用相关参数defaults调用this()来使重载构造函数引用的单个主构造函数。这样做的原因是它使得对象的构造状态变得更加清晰 - 实际上你可以将主构造函数看作唯一真正的构造函数,其他人只是委托给它
其中一个例子可能是JTable - 主构造函数采用TableModel(加上列和选择模型),其他构造函数调用此主构造函数。
对于超类已经重载构造函数的子类,我倾向于认为将任何父类的构造函数视为主类并且认为没有单个主构造函数是完全合法的。例如,当扩展Exception时,我经常提供3个构造函数,一个只接受String消息,一个接受Throwable原因而另一个接受两者。这些构造函数中的每一个都直接调用super。
我认为"已经重载的类"意味着基类有几个重载的构造函数。
是的,这就是我的意思。
我已经从这个澄清中修改了我的答案
我同意第一部分,但不是关于继承已经重载的类的第二部分:让我说我继承Exception到一个新类,我希望Exceptions字符串将以bla开头 - 这意味着我应该在构造函数接收中验证它字符串。如果我不像在基类中那样调用主构造函数,我必须复制此验证的代码。
我认为这是不必要的限制。
@Tom - 在某些情况下,我偏离了这种做法,但我总是仔细考虑这样做,因为我相信没有一个主要的构造函数是一个混乱的类设计的良好指标。
如果您有一个非常复杂的类,其中包含许多选项,其中只有一些组合有效,请考虑使用Builder。在代码方面也很有效但在逻辑上也很好。
Builder是一个嵌套类,其方法仅用于设置字段,然后ComplexClass构造函数仅将此类构建器作为参数。
编辑:ComplexClass构造函数可以确保Builder中的状态有效。如果你只是在ComplexClass上使用setter,这很难做到。
非常同意使用构建器模式,像OP这样的加载构造函数是非常糟糕的主意,因为它不符合最小惊喜的原则。
它实际上取决于类的类型,因为并非所有类都是相同的。
作为一般准则,我建议2个选项:
对于值和不可变类(Exception,Integer,DTO等),请使用上面答案中建议的单个主构造函数
对于其他所有内容(会话bean,服务,可变对象,JPA和JAXB实体等),只使用默认构造函数,并在所有属性上使用合理的默认值,以便无需其他配置即可使用
好吧,这是重载构造函数的一个例子。
public class Employee
{
private String name;
private int age;
public Employee()
{
System.out.println("We are inside Employee() constructor");
}
public Employee(String name)
{
System.out.println("We are inside Employee(String name) constructor");
this.name = name;
}
public Employee(String name, int age)
{
System.out.println("We are inside Employee(String name, int age) constructor");
this.name = name;
this.age = age;
}
public Employee(int age)
{
System.out.println("We are inside Employee(int age) constructor");
this.age = age;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
}
在上面的示例中,您可以看到重载的构造函数。构造函数的名称相同,但每个构造函数具有不同的参数。
这里有一些资源可以更好地解释java中的构造函数重载,
构造函数。
构造函数说明。
似乎写这个答案的努力非常少。 OP知道什么是构造函数重载。答案就是这样解释的。