簡體   English   中英

某些參數沒有默認參數值的多個構造函數

[英]Multiple Constructors with no default parameter value for some parameters

如果您需要創建多個構造函數,直接的解決方案是鏈接構造函數。 一個構造函數使用一些默認值調用另一個構造函數。 但是如果沒有默認值怎么辦?

例如具有以下三個構造函數的 class :

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

我不想在多個構造函數中驗證相同的字段,所以我會嘗試讓構造函數 23調用構造函數 1

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
    {                   
        this(prerson, SomeEnum.NO_VALUE);
    }

    public MyClass(SomeEnum enum1)  // constructor 3
    {               
        this(?, enum1);
    }

因此,假設我們在SomeEnum中有一些默認值,但是對於構造函數 3 ,我沒有Person的默認值。 我可以更改調用鏈並使構造函數 1 和 2 調用構造函數 3,然后自己驗證和設置 Person,但我不希望 Person 驗證在兩個地方。

我也不喜歡創建一些擴展Person並使用它的NotPerson object 的想法。 建造者模式也不適合我。 此外,驗證可能比僅檢查 null 更復雜。

如果您的問題主要是重復檢查,那么Project Lombok可以輕松解決這個問題。 它將自動生成等效代碼。 它默認使用 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;     
}

一種方法是編寫私有 static 驗證方法。 使用它們的緊湊方式如下所示:

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

用途

MyClass myClass = new MyClass(person, enum1);
MyClass myClass = new MyClass(person);
MyClass myClass = new MyClass(enum1);

您也可以使用 static 構造方法來做到這一點,如果存在歧義,有助於澄清 arguments,方法是不同地命名 static 方法:

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

用途

MyClass myClass = MyClass.of(person, enum1);
MyClass myClass = MyClass.of(person);
MyClass myClass = MyClass.of(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;
}

用途

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM