Java 多个构造函数,某些参数没有默认参数值
如果您需要创建多个构造函数,直接的解决方案将是链接这些构造函数。一个构造函数使用一些默认值调用另一个构造函数。 但是如果没有默认值呢 例如,具有以下三个构造函数的类:Java 多个构造函数,某些参数没有默认参数值,java,constructor,Java,Constructor,如果您需要创建多个构造函数,直接的解决方案将是链接这些构造函数。一个构造函数使用一些默认值调用另一个构造函数。 但是如果没有默认值呢 例如,具有以下三个构造函数的类: public MyClass(Person person, SomeEnum enum1) // constructor 1 { if (person== null) { throw new IllegalArgumentException("person cannot be null.");
public MyClass(Person person, SomeEnum enum1) // constructor 1
{
if (person== null)
{
throw new IllegalArgumentException("person cannot be null.");
}
if (enum1== null)
{
throw new IllegalArgumentException("enum1 cannot be null.");
}
this.person= person;
this.enum1 = enum1;
}
public MyClass(Person person) // constructor 2
{
if (person== null)
{
throw new IllegalArgumentException("person cannot be null.");
}
this.person= person;
}
public MyClass(SomeEnum enum1) // constructor 3
{
if (enum1== null)
{
throw new IllegalArgumentException("enum1 cannot be null.");
}
this.enum1 = enum1;
}
我不想在多个构造函数中验证相同的字段,因此我将尝试让构造函数2和3调用构造函数1:
假设我们在SomeEnum中有一些默认值,但是对于构造函数3,我没有Person的默认值。
我可以更改调用链,让构造函数1和2调用构造函数3,然后自己验证和设置Person,但我不希望Person验证出现在两个地方
我也不喜欢创建一些NotPerson对象来扩展Person并使用它。
构建器模式也不适合我。
此外,验证可能比检查null更复杂。一种方法是编写私有静态验证方法。使用它们的紧凑方式如下所示:
public MyClass(Person person, SomeEnum enum1) {
this.person = validatePerson(person);
this.enum1 = validateSomeEnum(enum1);
}
public MyClass(Person person) {
this.person = validatePerson(person);
}
public MyClass(SomeEnum enum1) {
this.enum1 = validateSomeEnum(enum1);
}
private static Person validatePerson(Person person) {
if (person == null) {
throw new IllegalArgumentException("person cannot be null.");
}
return person;
}
private static SomeEnum validateSomeEnum(SomeEnum enum1) {
if (enum1 == null) {
throw new IllegalArgumentException("enum1 cannot be null.");
}
return enum1;
}
使用
您还可以使用静态构造方法来实现这一点,通过对静态方法进行不同的命名,有助于澄清存在歧义的参数:
public static MyClass of(Person person, SomeEnum enum1) {
validatePerson(person);
validateSomeEnum(enum1);
return new MyClass(person, enum1);
}
public static MyClass of(Person person) {
validatePerson(person);
return new MyClass(person, null);
}
public static MyClass of(SomeEnum enum1) {
validateSomeEnum(enum1);
return new MyClass(null, enum1);
}
private static void validatePerson(Person person) {
if (person == null) {
throw new IllegalArgumentException("person cannot be null.");
}
}
private static void validateSomeEnum(SomeEnum enum1) {
if (enum1 == null) {
throw new IllegalArgumentException("enum1 cannot be null.");
}
}
private MyClass(Person person, SomeEnum enum1) {
this.person = person;
this.enum1 = enum1;
}
使用
另一个选项是生成器模式,如果有许多可选属性,则该模式尤其有用:
public static final class Builder {
private Person person;
private SomeEnum enum1;
public Builder withPerson(Person person) {
if (person == null) {
throw new IllegalArgumentException("person cannot be null.");
}
this.person = person;
return this;
}
public Builder withSomeEnum(SomeEnum enum1) {
if (enum1 == null) {
throw new IllegalArgumentException("enum1 cannot be null.");
}
this.enum1 = enum1;
return this;
}
public MyClass create() {
if (this.person == null && this.enum1 == null) {
throw new IllegalArgumentException("One of person or enum1 is required.");
}
return new MyClass(this.person, this.enum1);
}
}
private MyClass(Person person, SomeEnum enum1) {
this.person = person;
this.enum1 = enum1;
}
使用
如果您的问题主要是重复检查,则可以轻松解决此问题。它将自动生成等效代码。默认情况下,它使用NullPointerException,但如果需要,可以配置为使用IllegalArgumentException
public MyClass(@NonNull Person person, @NonNull SomeEnum enum1) {
this.person = person;
this.enum1 = enum1;
}
public MyClass(@NonNull Person person) {
this.person = person;
}
public MyClass(@NonNull SomeEnum enum1) {
this.enum1 = enum1;
}
另一个解决方案是更好地重新安排链调用:
public MyClass(Person person, SomeEnum enum1) // constructor 1
{
this(enum1);
if (person== null)
{
throw new IllegalArgumentException("person cannot be null.");
}
this.person= person;
}
public MyClass(Person person) // constructor 2
{
this(person, SomeEnum.NoValue);
}
public MyClass(SomeEnum enum1) // constructor 3
{
if (enum1== null)
{
throw new IllegalArgumentException("enum1 cannot be null.");
}
this.enum1 = enum1;
}
将验证提取到方法中?在第一个示例构造函数2中,构造后字段
enum1
的状态应该是什么?无效的同样地,第一个示例构造函数3,字段person
的状态应该是什么?如果必须提供两个参数,则两个单参数构造函数都不可能是合法的,除非它们都有合理的默认值,您没有提到。你的问题没有意义。this(null,enum1)代码>?我不认为验证应该是不同的c'tor(我的意思是验证逻辑,而不是方法),因此-在第三个c'tor中,您不应该将person保留为null,因为根据第一个c'tor它是无效的。问题很简单-person的默认值是什么-如果为null,第一个不要失败,如果是其他的-在第三个中使用它。一旦你解决了这个问题,使用第一个c'tor(或构建器)就是ClearThanks,我认为第一个解决方案是三者中最好的,因为在我的例子中,我有很多类扩展了MyClass,而不是使用super来调用不同MyClass的构造函数。
public static final class Builder {
private Person person;
private SomeEnum enum1;
public Builder withPerson(Person person) {
if (person == null) {
throw new IllegalArgumentException("person cannot be null.");
}
this.person = person;
return this;
}
public Builder withSomeEnum(SomeEnum enum1) {
if (enum1 == null) {
throw new IllegalArgumentException("enum1 cannot be null.");
}
this.enum1 = enum1;
return this;
}
public MyClass create() {
if (this.person == null && this.enum1 == null) {
throw new IllegalArgumentException("One of person or enum1 is required.");
}
return new MyClass(this.person, this.enum1);
}
}
private MyClass(Person person, SomeEnum enum1) {
this.person = person;
this.enum1 = enum1;
}
MyClass myClass = new MyClass.Builder()
.withPerson(person)
.withSomeEnum(enum1)
.create();
MyClass myClass = new MyClass.Builder()
.withPerson(person)
.create();
MyClass myClass = new MyClass.Builder()
.withSomeEnum(enum1)
.create();
public MyClass(@NonNull Person person, @NonNull SomeEnum enum1) {
this.person = person;
this.enum1 = enum1;
}
public MyClass(@NonNull Person person) {
this.person = person;
}
public MyClass(@NonNull SomeEnum enum1) {
this.enum1 = enum1;
}
public MyClass(Person person, SomeEnum enum1) // constructor 1
{
this(enum1);
if (person== null)
{
throw new IllegalArgumentException("person cannot be null.");
}
this.person= person;
}
public MyClass(Person person) // constructor 2
{
this(person, SomeEnum.NoValue);
}
public MyClass(SomeEnum enum1) // constructor 3
{
if (enum1== null)
{
throw new IllegalArgumentException("enum1 cannot be null.");
}
this.enum1 = enum1;
}