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

cev*_*ing 16 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

该类包含两个可选值,我想提供所有可能的构造函数排列.第一个版本不初始化任何内容,第二个版本仅初始化第一个值,第三个版本仅初始化第二个值.

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

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

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

Seb*_*edl 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; }
Run Code Online (Sandbox Code Playgroud)

  • 一个选项是使字段"final"并让默认构造函数调用`this(null,null);` (12认同)
  • @MichaelShopsin为什么会有例外 (3认同)
  • @MichaelShopsin ctor链接最后的作品给我,想一个构造函数!=一个方法. (2认同)

Jon*_*eet 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;
}
Run Code Online (Sandbox Code Playgroud)

那样:

  • 只有一个地方设置字段,并设置所有字段
  • 从任何其他构造函数,您可以指定(并告诉您何时读取代码)其他字段的"默认"值.

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

注意这样,如果你有(比方说)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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

public static Pair fromSecond(Integer second) {
    return new Pair(null, second);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 伙计们,我觉得讨论"汽车"和"cdr"的命名真的是主题,这里有点吵;-) (3认同)

fge*_*fge 8

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

除此之外,这种模式允许你不要有涵盖所有情况的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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

样品用法:

final Pair newPair = Pair.newBuilder.withCar("foo").withCdr(1).build();
Run Code Online (Sandbox Code Playgroud)

优势:Pair现在是不变的!

  • @ Chips_100我已经习惯了这样做,另一方面,我可能会错过一些重点...例如,DI框架(Dependecy Injection). (2认同)

Lau*_*ntG 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;
    }
}
Run Code Online (Sandbox Code Playgroud)