【问题标题】:How to avoid constructor code redundancy in Java?如何避免 Java 中的构造函数代码冗余?
【发布时间】:2013-06-14 19:02:49
【问题描述】:

我有以下课程:

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 方法)?

【问题讨论】:

  • this() 和 super() 的问题必须是[构造函数中的第一个语句][1]。 [1]:stackoverflow.com/questions/1168345/…
  • 你调用 this(...) 构造函数两次,你只能让一个构造函数调用另一个构造函数,并且链式构造函数调用必须是构造函数中的第一个语句。

标签: java


【解决方案1】:

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

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; }

【讨论】:

  • 一个选项是创建字段final 并让默认构造函数调用this(null, null);
  • 构造函数调用其父级的规则的例外是最终变量。对于带有最终变量的 Pair 版本,代码如下所示:class pair { private final String car; private final Integer cdr; public Pair() { this.car = null; this.cdr = null; } public Pair(String car) { this.car = car; this.cdr = null; } ... }
  • @MichaelShopsin 为什么会有例外
  • @MichaelShopsin ctor 链接到我的最终作品,认为是构造函数!= 方法。
  • @josefx 你是对的,我从来没有尝试过只调用其他构造函数的方法。
【解决方案2】:

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

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 类设为泛型,而不必担心如果两个类型参数相同,将调用哪个构造函数。此外,任何阅读代码的人都可以理解将要构造的内容,而无需检查参数的类型。

【讨论】:

  • @ceving:在我看来,这在 Java 的上下文中是一个非常模糊的含义......特别是因为它们是 operators 而不是 。如果这些只是“第一”和“第二”值,那么这些名称对大多数人来说会更有意义。
  • 伙计们,我觉得讨论carcdr 的命名实在是离题,这里有点吵;-)
  • 这只是一个例子。如果您更熟悉它们,我可以将其更改为foobar
  • @ceving:正如 Jon 所说,最好将它们重命名为 firstsecond。你这里有一个 2 元组,而不是一个 cons 单元格。
【解决方案3】:

您可能正在这里寻找builder pattern

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

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

【讨论】:

  • 构建器模式的好且全面的示例,但在这种情况下可能有点矫枉过正。 (另外,我认为不变性并不是自动的优势)。但仍然 +1 是一个不错的选择!
  • @Chips_100 我已经习惯这样做了,另一方面,我可能会错过一些重要的点......例如,DI框架(依赖注入)。
【解决方案4】:
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;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-28
    • 1970-01-01
    • 2017-09-16
    • 1970-01-01
    相关资源
    最近更新 更多