16

我有以下课程:

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:调用 this 必须是构造函数中的第一条语句
        这(cdr);
            ^
1 个错误

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

4

4 回答 4

52

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

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; }
于 2013-06-18T14:06:49.130 回答
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类成为通用类,而不必担心如果两个类型参数相同,将调用哪个构造函数。此外,任何阅读代码的人都可以理解将要构造的内容,而无需检查参数的类型。

于 2013-06-18T14:07:51.263 回答
8

您可能正在这里寻找构建器模式

除其他外,此模式允许您不必拥有涵盖所有情况的无数构造函数。对于您的情况,这可能是:

@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现在是不可变的!

于 2013-06-18T14:11:29.700 回答
5
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;
    }
}
于 2013-06-18T14:07:26.280 回答