5

我使用 Joshua Bloch 的 Builder 模式编写了一个类,类似于这个 Pizza 示例:

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. 类不能被实例化并且不提供任何静态方法或字段。不能使用具有私有构造函数且没有任何静态方法或字段的类。

我应该忽略这些警告吗?

Pizza另一个问题:类中的私有字段Builder是重复的。当私有字段的数量变大时,这会很烦人。有什么办法可以避免吗?

4

2 回答 2

2

关于如何删除重复。

我会得到更多的反对票:) 但也许是这样的?

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() {
}
}
于 2011-05-30T12:20:50.623 回答
1

Pizza 和 Builder 类中的私有字段是重复的。当私有字段的数量变大时,这会很烦人。有什么办法可以避免吗?

我个人通过使用包含所有字段的第三个私有静态值对象类来解决这个问题,并在构建器和主类中使用它(字段访问由委托处理)。当然,这最终可能会增加行数/类数,但如果您的构建器最终因大量字段和检查而变得复杂,这将是非常宝贵的。

此外,实际上在 Pizza 类上提供一个静态方法也没有什么坏处,该方法使用必填字段构建 Pizza 对象。当然,除非您不确定必填字段是什么,或者担心必填字段在您的课程演变过程中可能会发生变化。重点是,只要您经过深思熟虑后可以证明自己的行为是正当的(就像 Joshua Bloch 所说的那样),您就可以放心地忽略这些警告,因为您知道自己在做什么。:-)

一次性片段:

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

}
于 2011-05-30T09:41:53.020 回答