Java 如何确保我的bean被正确构建?

Java 如何确保我的bean被正确构建?,java,javabeans,builder,Java,Javabeans,Builder,我正在使用构建器模式构建JavaBean(仅字段和getter/setter) 在本例中,假设这是我们的bean: public class Pizza { private int size; private boolean cheese; private boolean pepperoni; private boolean bacon; private Pizza(Builder builder) { size = builder.size; cheese

我正在使用构建器模式构建JavaBean(仅字段和getter/setter)

在本例中,假设这是我们的bean:

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

  private Pizza(Builder builder) {
    size = builder.size;
    cheese = builder.cheese;
    pepperoni = builder.pepperoni;
    bacon = builder.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);
    }
  }
}
摘自

现在,我一直在努力确保
Pizza
中的所有字段都是非空的,通过反射,迭代
Pizza
中的字段并检查它们是否为空,但在检查发生之前,似乎没有设置我的字段(这里我可能错了)。Jon Skeet是我用来检查字段是否为非空的内容(而不是计数,而是抛出异常)

然后,我尝试检查构建器的字段,但是在构建器中有额外的字段(例如,我有一个XMLParser字段,它可能为空)。按pizza字段子集生成器字段不起作用,因为它们具有不同的“包路径”(?),例如,
org.GiusepesPizzaria.pizza.size
org.GiusepesPizzaria.builder.size

有没有更好的方法来检查这个?在实现反射方法之前,我使用了这种构造:

if(builder.size ==null){
    throw new BadPizzaException("Eh, what're ya doin'?"+
             " Pizza Size was not set correctly");
}else{
    size=builder.size;
}
但是,如果你有大约10个字段要检查的话,它最终会变成一个冗长、混乱的简单类

这就是我尝试过的。有更好的方法吗?

试试这个:

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

    private Pizza()
    {
        throw new UnsupportedOperationException();
    }

    Pizza(
        final int theSize,
        final boolean theCheese,
        final boolean thePepperoni,
        final boolean theBacon)
    {
        bacon = theBacon;
        cheese = theCheese;
        pepperoni = thePepperoni;
        size = theSize;
    }
}

// new file.
public class PizzaBuilder
{
    private boolean bacon;
    private boolean cheese;
    private boolean pepperoni;
    private int size;

    public PizzaBuilder()
    {
        size = 9; // default size.
    }

    public void setHasBacon()
    {
        bacon = true;
    }

    public void setHasNoBacon()
    {
        bacon = false;
    }

    public void setHasCheese()
    {
        cheese = true;
    }

    public void setHasNoCheese()
    {
        cheese = false;
    }

    public void setHasPepperoni()
    {
        pepperoni = true;
    }

    public void setHasNoPepperoni()
    {
        pepperoni = false;
    }

    public void setSizeNineInch()
    {
        size = 9;
    }

    public void setSizeTwelveInch()
    {
        size = 12;
    }

    public Pizza buildPizza()
    {
        return new Pizza(size, cheese, pepperoni, bacon);
    }
}
有了上面的建筑商,建筑商不可能生产出无效的比萨饼

假设:仅支持9英寸和12英寸比萨饼。根据需要添加更多设置大小


构建器使用我所说的NMsetter。此样式设置器允许您设置值,但不公开所述值的实现。这似乎不是我的原创发明。

确保设置所有变量的一个有趣模式是使用,其中第一个setter只允许设置第二个,第二个只允许设置第三个,依此类推。当您完成最后一步时,您可以构建该类,到那时您将知道所有方法都已被调用

那篇文章的简短摘录:

Panino solePanino = PaninoStepBuilder.newBuilder()
        .paninoCalled("sole panino")
        .breadType("baguette")
        .fish("sole")
        .addVegetable("tomato")
        .addVegetable("lettece")
        .noMoreVegetablesPlease()
        .build();

您必须从panino的名称开始,然后是面包类型。

字段是否设置不应是“可能”的情况。一旦你设置了它们,它们就被设置好了。但是,请确保您测试的字段是正确的:那些在
Builder
中的字段,而不是在
Pizza
中的字段@MarkoTopolnik中的字段。我正在从内存复制这些方法。如果有机会,我会去更新我的问题。一般的问题仍然存在。一般来说,反射是大规模
null
检查的好方法。