2011-05-30 40 views
4

我已经写了使用约书亚布洛赫的Builder模式,这类似于这个比萨例子类:约书亚布洛赫的Builder模式和PMD警告

public class Pizza { 
    private int size; 
    private boolean cheese; 
    private boolean pepperoni; 
    private boolean bacon; 

    public static class Builder { 
    //required 
    private final int size; 

    //optional 
    private boolean cheese = false; 
    private boolean pepperoni = false; 
    private boolean bacon = false; 

    public Builder(int size) { 
     this.size = size; 
    } 

    public Builder cheese(boolean value) { 
     cheese = value; 
     return this; 
    } 

    public Builder pepperoni(boolean value) { 
     pepperoni = value; 
     return this; 
    } 

    public Builder bacon(boolean value) { 
     bacon = value; 
     return this; 
    } 

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

    private Pizza(Builder builder) { 
    size = builder.size; 
    cheese = builder.cheese; 
    pepperoni = builder.pepperoni; 
    bacon = builder.bacon; 
    } 
} 

但PMD报道2个警告:

  1. (指着到方法Builder.build()) 避免通过构造函数的类之外的私有构造函数来实例化 。 通过 构造函数的类之外的构造函数实例化私有 通常会导致 生成一个访问器。工厂 方法或者构建器的未授权化可以消除这种情况。生成的类文件 实际上是一个接口。它给 访问类能力 调用一个新的隐藏包范围 构造函数,它将接口 作为补充参数。这 变成一个私人构造函数 有效地与包 范围之一,并有挑战 辨别。
  2. 类不能实例化, 不提供任何静态方法 或字段。一个拥有专用 构造函数并且没有任何 静态方法或字段的类不能使用 。

我应该忽略这些警告吗?

另一个问题:类PizzaBuilder中的私有字段是重复的。当私人领域的数量变大时,这将会令人讨厌。有什么办法可以避免它?

+0

for 1.你也许可以定义你的Pizza构造函数为package-protected。这也应该解决2. – Rom1 2011-05-30 09:33:47

+8

模式是一个很好的; PMD只是愚蠢的。我个人会忽略它。 – skaffman 2011-05-30 09:43:05

+0

只是一个侧面说明:我一直在使用一个名为[Make-It-Easy](http://code.google.com/p/make-it-easy/)的小框架,这有助于构建这个* builders *和代码是非常可读的。我主要将它用于我的单元测试,但它可以绝对用于生产代码。 – Augusto 2011-05-30 09:58:05

回答

2

有关如何删除重复。

我会得到更多的downvotes :)但也许这样的事情?

class Pizza { 
private int size; 
private boolean cheese; 
private boolean pepperoni; 
private boolean bacon; 

public static class Builder { 
    private Pizza pizza = new Pizza(); 

    public Builder(int size) { 
     pizza.size = size; 
    } 

    public Builder cheese(boolean value) { 
     pizza.cheese = value; 
     return this; 
    } 

    public Builder pepperoni(boolean value) { 
     pizza.pepperoni = value; 
     return this; 
    } 

    public Builder bacon(boolean value) { 
     pizza.bacon = value; 
     return this; 
    } 

    public Pizza build() { 
     return pizza; 
    } 
} 

private Pizza() { 
} 
} 
+0

我认为这是一个很好的解决方案,以消除重复。 – chance 2011-05-30 12:49:22

+6

我不喜欢这样。您可以通过调用build()后创建它的Builder更改比萨上的字段。构建器模式的最佳用途之一是简化不可变类的创建。 – Kenny 2012-08-08 12:43:57

+0

对不起,但以这种风格,你仍然会得到:1)“避免通过构造函数的类之外的私有构造函数实例化。”和2)“类不能实例化,不提供任何静态方法或字段”,所以问题没有解决。 – aloplop85 2013-08-26 08:25:33

1

类比萨的私人领域和 生成器是重复的。这将是 恼人的时候私人 领域越来越大。有没有 的方法来避免它?

我个人通过使用包含所有字段并在构建器和主类中使用它的第三个私有静态值对象类(字段访问由委派处理)来解决此问题。当然,这可能会导致行数/班数膨胀,但如果您的建设者最终会因大量的领域和检查而变得复杂,那么这种方法是无价的。

此外,它不会伤害到实际上提供了一个比萨类的建立一个比萨对象与必填字段的静态方法。除非你不确定这些强制性领域是什么,或者担心强制性领域在你的课堂演变过程中可能会发生变化。要指出的是,只要你能够在经过很多思考后证明你的行为正确(像约书亚布洛赫所说的那样),你就可以放心地忽略那些知道你知道自己在做什么的警告。 :-)

暴殄天物一个片段:

public class Pizza { 

    private final PizzaVO vo; 

    private static class PizzaVO { 

     int size; 

     boolean cheese; 

     boolean pepperoni; 

     boolean bacon; 
    } 

    public static class Builder { 

     private final PizzaVO vo = new PizzaVO(); 

     public Builder(int size) { 
      vo.size = size; 
     } 

     public Builder cheese(boolean value) { 
      vo.cheese = value; 
      return this; 
     } 

     public Builder pepperoni(boolean value) { 
      vo.pepperoni = value; 
      return this; 
     } 

     public Builder bacon(boolean value) { 
      vo.bacon = value; 
      return this; 
     } 

     public Pizza build() { 
      return new Pizza(vo); 
     } 
    } 

    private Pizza(PizzaVO vo) { 
     this.vo = vo; 
    } 

    public int getSize() { 
     return vo.size; 
    } 

    // other getter setter methods as per your taste 

} 
+2

这不值得使用这种风格。问题没有解决。 – aloplop85 2013-08-26 08:26:14

+0

hi aloplop85,你能澄清哪些问题没有解决,为什么? – sudocoder 2015-01-28 02:20:55

+0

@sudocoder至少出现PMD错误“避免通过构造函数的类之外的私有构造函数实例化”。将仍然存在 – Shannon 2017-06-29 01:00:24