2017-08-15 47 views
1

我實現了基於模式這answer 我有以下asbtract配置:Builder模式

public abstract class AbstractConfig { 

    public static abstract class Builder<B extends Builder<B>> { 

     private int calories = 0; 

     public Builder() { 

     } 

     public B setCalories(int calories) { 
      this.calories = calories; 
      return (B) this; 
     } 

     public abstract AbstractConfig build(); 
    } 

    private int calories = 0; 

    protected AbstractConfig(final Builder builder) { 
     calories = builder.calories; 
    } 
} 

而且我有以下具體配置:

public class DialogConfig extends AbstractConfig { 

    public static class DialogConfigBuilder<B extends DialogConfigBuilder<B>> extends Builder<B> { 

     private double width; 

     private double height; 

     public DialogConfigBuilder() { 
      //does nothing. 
     } 

     public B setWidth(final double value) { 
      width = value; 
      return (B) this; 
     } 

     public B setHeight(final double value) { 
      height = value; 
      return (B) this; 
     } 
     public DialogConfig build() { 
      return new DialogConfig(this); 
     } 
    } 

    private final double width; 

    private final double height; 

    protected DialogConfig(final DialogConfigBuilder builder) { 
     super(builder); 
     width = builder.width; 
     height = builder.height; 
    } 

    public double getWidth() { 
     return width; 
    } 

    public double getHeight() { 
     return height; 
    } 
} 

這是我如何使用它

DialogConfig config = new DialogConfig.DialogConfigBuilder() 
       .setWidth(0) 
       .setCalories(0) 
       .setHeight(0) //X LINE 
       .build(); 

在X l我得到 - 找不到符號方法setHeight。我的錯誤是什麼?

EDIT - 我將擁有一個ExtendedDialogConfig,它必須擴展DialogConfig等。我的意思是會有其他的子類。

+2

您正在使用原始類型,這意味着'B'解析爲'Builder'。將類聲明更改爲'DialogConfigBuilder extends Builder '類。 – shmosel

+0

請注意,您應該謹慎複製該解決方案,因爲它也[使用原始類型](https://stackoverflow.com/questions/17164375/subclassing-a-java-builder-class/17165079#comment59589591_17165079)。 – shmosel

+0

@shmosel比你的評論。但是如果我更改爲類DialogConfigBuilder extends Builder '我可以在SuperDialogConfig中擴展DialogConfig嗎?我認爲,如果我按照你的建議,然後setCalories()將返回DialogConfig但不是SuperDialogConfig。 –

回答

1

我發現我錯了。這是我用DialogConfigBuilder

DialogConfig config = new DialogConfig.DialogConfigBuilder() 
       .setWidth(0) 
       .setCalories(0) 
       .setHeight(0) //X LINE 
       .build(); 

這是我應該如何在第二種情況下使用DialogConfigBuilder

DialogConfig config = new DialogConfig.DialogConfigBuilder<>() 
       .setWidth(0) 
       .setCalories(0) 
       .setHeight(0) //X LINE 
       .build(); 

注重<>

+0

你應該接受你的自我回答。也許可以在第一行寫上「我的錯誤是使用** raw **類型,現在我明白了爲什麼大家都說*不使用** raw **類型*」;-) – GhostCat

2

你會先改變setCalories()到:

public Builder<B> setCalories(int calories) { 
    this.calories = calories; 
    return this; 
} 

擺脫那個演員和警告。現在仔細看看這個。您將返回一個生成器。此代碼不知道未來的子類。它只返回該基礎構建器的一個實例。

因此,當你有一個鏈接的電話:

.setHeight(0) .build(); 

,將返回基地建設者。然後致電build() - 這將構建一個摘要配置。但是你想把它分配給更具體的DialogConfig。因此錯誤。

A(難看)解決方法:

DialogConfig.DialogConfigBuilder<?> builder = new DialogConfig.DialogConfigBuilder<>().setHeight(0); 
builder.setCalories(0); 

...config = builder.build(); 

而一個溶液 - 通過再次返工setCalories()

@SuppressWarnings("unchecked") 
public <T extends B> T setCalories(int calories) { 
    this.calories = calories; 
    return (T) this; 
} 

修正編譯錯誤;並允許鏈接setCalories()調用。最後演習擺脫演員/壓制是作爲練習留給讀者。

並記錄在案 - 「完整」的解決方案,包括所有adaptions擺脫原始類型和其他警告:

abstract class AbstractConfig { 
    public static abstract class Builder<B extends Builder<B>> { 
     private int calories = 0; 

     @SuppressWarnings("unchecked") 
     public <T extends B> T setCalories(int calories) { 
      this.calories = calories; 
      return (T) this; 
     } 

     public abstract AbstractConfig build(); 
    } 

    private int calories = 0; 
    public int getCalories() { return calories; } 

    protected <B extends Builder<B>> AbstractConfig(final Builder<B> builder) { 
     calories = builder.calories; 
    } 
} 

final class DialogConfig extends AbstractConfig { 
    public static class DialogConfigBuilder<B extends DialogConfigBuilder<B>> extends Builder<B> { 

     private double width;  
     private double height; 

     public DialogConfigBuilder<B> setWidth(final double value) { 
      width = value; 
      return this; 
     } 

     public DialogConfigBuilder<B> setHeight(final double value) { 
      height = value; 
      return this; 
     } 

     public DialogConfig build() { 
      return new DialogConfig(this); 
     } 
    } 

    private final double width; 
    private final double height; 

    protected <B extends DialogConfigBuilder<B>> DialogConfig(final DialogConfigBuilder<B> builder) { 
     super(builder); 
     width = builder.width; 
     height = builder.height; 
    } 

    public double getWidth() { return width; } 
    public double getHeight() { return height; } 
} 

public class Builders { 
    public static void main(String[] args) { 
     DialogConfig config = new DialogConfig.DialogConfigBuilder<>().setHeight(0).setCalories(0).build(); 
     System.out.println(config); 
    } 
} 
+0

在你的解決方案中,你做了DialogConfig final,並且除了DialogConfigBuilder中的所有setter返回DialogConfigBuilder。這不是我需要的。我寫過,我需要在其他子類中擴展DialogConfig,每個子類都必須實現構建器模式。 –

+0

@Pavel_K這不是**我的**代碼。我從你的輸入中複製了這部分內容。再次 - 這只是爲了完成給定任務的輸入。當您從該課程中刪除「final」時,沒有任何變化。而改變後的返回類型是關於**擺脫拋出和警告! – GhostCat

+0

我需要一些時間來檢查 –