如何避免Java中的构造函数代码冗余?
我有以下课程:如何避免Java中的构造函数代码冗余?,java,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);
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
java:13:对这个函数的调用必须是构造函数中的第一条语句
这个(cdr);
^
1错误
是否可以在没有任何代码冗余的情况下编写最后一个构造函数(也不调用相同的setter方法)?通常,参数较少的构造函数应该调用参数较多的构造函数
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; }
以相反方向链接构造函数,最具体的是设置所有字段的构造函数:
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;
}
这样:
- 只有一个位置设置字段,它设置所有字段
- 从任何其他构造函数中,可以指定(并在读取代码时告知)其他字段的“默认”值
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);
}
此时,您可以将
对
类设置为泛型,而不必担心如果两个类型参数相同,将调用哪个构造函数。此外,任何阅读代码的人都可以理解将要构造的内容,而不必检查参数的类型。您可能正在此处查找
除此之外,此模式允许您不必拥有覆盖所有情况的大量构造函数。对于您的情况,这可能是:
@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
现在是不可变的 一个选项是将字段设置为final,并让默认构造函数调用this(null,null)代码>构造函数调用其父级规则的例外是final变量。对于带有最终变量的Pair版本,代码如下:类Pair{private final String car;private final Integer cdr;public Pair(){this.car=null;this.cdr=null;}公共Pair(String car){this.car=car;this.cdr=null;}…}
@MichaelShopsin为什么会有exception@MichaelShopsin一个建造师想,我要把最后的作品链接起来一个方法。@josefx你是对的,我从来没有尝试过只调用其他构造函数的方法。@ceving:在Java上下文中,这似乎是一个相当模糊的意思。。。特别是因为它们是运算符而不是值。如果这些只是“第一”和“第二”值,那么这些名称对大多数人来说会更有意义。伙计们,我觉得讨论car
和cdr
的命名真的是离题了,这里有点吵;-)这只是一个例子。如果您更熟悉它们,我可以将其更改为foo
和bar
。@ceving:正如Jon所说,最好将它们重命名为first
和second
。这里有一个2元组,而不是cons单元格。对于构建器模式来说,这是一个很好的全面示例,但在本例中可能有点过头了。(而且,我认为不变性并不自动成为优势)。但仍然+1是一个不错的选择@我已经习惯了这样做,另一方面,我可能会错过一些要点。。。例如,DI框架(依赖注入)。this()和super()的问题必须是[构造函数中的第一条语句][1]。[1] :调用this(…)构造函数两次,只能让一个构造函数调用另一个构造函数,链式构造函数调用必须是构造函数中的第一条语句。
final Pair newPair = Pair.newBuilder.withCar("foo").withCdr(1).build();