如何避免Java中的构造函数代码冗余?

时间:2013-06-18 14:04:31

标签: java

我有以下课程:

class Pair
{
    String car;
    Integer cdr;

    public Pair () {}
    public Pair (String car) { this.car = car; }
    public Pair (Integer cdr) { this.cdr = cdr; }

    public Pair (String car, Integer cdr)
    {
        this(car);
        this(cdr);
    }
}

该类包含两个可选值,我想提供所有可能的构造函数排列。第一个版本没有初始化任何东西,第二个版本只初始化第一个值,第三个版本只初始化第二个值。

最后一个构造函数是第二个和第三个构造函数的组合。但是不可能把它写下来,因为代码失败了。

constructor.java:13: call to this must be first statement in constructor
        this(cdr);
            ^
1 error

是否可以编写最后一个没有任何代码冗余的构造函数(也没有调用相同的setter方法)?

4 个答案:

答案 0 :(得分:51)

通常,参数较少的构造函数应该调用具有更多参数的构造函数。

public Pair() {}
public Pair(String car) { this(car, null); }
public Pair(Integer cdr) { this(null, cdr); }
public Pair(String car, Integer cdr) { this.car = car; this.cdr = cdr; }

答案 1 :(得分:19)

将构造函数链接到相反的方向,最具体的是设置所有字段的构造函数:

public Pair() {
    this(null, null); // For consistency
}

public Pair(String car) {
    this(car, null);
}

public Pair(Integer cdr) {
    this(null, cdr);
}

public Pair (String car, Integer cdr)  {
    this.car = car;
    this.cdr = cdr;
}

那样:

  • 只有一个位置设置字段,并设置所有字段
  • 从任何其他构造函数中,您可以指定(并告诉您何时阅读代码)其他字段的“默认”值。

顺便说一句,我强烈建议您将字段设为私有字段(可能是最终字段),并为其提供更有意义的名称。

注意这样,如果你有(比方说)5个参数和一个构造函数有3个,一个有4个,一个有5个,你可能选择从3开始链接 - > 4 - > 5,或者你可以直接从3 - > 5。

此外,您可能希望完全删除单参数构造函数 - 而使用静态方法会更具可读性,您可以在其中指定名称中的含义:

public static Pair fromCar(String car) {
    return new Pair(car, null);
}

public static Pair fromCdr(Integer cdr) {
    return new Pair(null, cdr);
}

或者在我喜欢的含义命名中:

public static Pair fromFirst(String first) {
    return new Pair(first, null);
}

public static Pair fromSecond(Integer second) {
    return new Pair(null, second);
}

此时,您可以使Pair类具有通用性,而不必担心如果两个类型参数相同,将调用哪个构造函数。此外,任何阅读代码的人都可以理解将要构建的内容,而无需检查参数的类型。

答案 2 :(得分:8)

您可能在这里寻找builder pattern

除此之外,这种模式允许你不要拥有涵盖所有案例的bazillion构造函数。对于您的情况,这可能是:

@Immutable // see JSR 305
public final class Pair
{
    private final String car;
    private final integer cdr;

    private Pair(final Builder builder)
    {
        car = builder.car;
        cdr = builder.cdr;
    }

    public static Builder newBuilder()
    {
        return new Builder();
    }

    // whatever other methods in Pair, including accessors for car and cdr, then:

    @NotThreadSafe // see JSR 305
    public final class Builder
    {
        private String car;
        private int cdr;

        private Builder()
        {
        }

        public Builder withCar(final String car)
        {
            this.car = car;
            return this;
        }

        public Builder withCdr(final int cdr)
        {
            this.cdr = cdr;
            return this;
        }

        public Pair build()
        {
            return new Pair(this);
        }
    }
}

样本用法:

final Pair newPair = Pair.newBuilder.withCar("foo").withCdr(1).build();

优势:Pair现在是不可变的!

答案 3 :(得分:6)

class Pair
{
    String car;
    Integer cdr;

    public Pair () {}
    public Pair (String car) { 
        this(car, null)
    }
    public Pair (Integer cdr) {
        this(null, cdr);
    }

    public Pair (String car, Integer cdr) {
        this.car = car;
        this.cdr = cdr;
    }
}