2017-08-15 29 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

我需要一些时间来检查 –