Joshua Bloch Builder and PMD alerts

I wrote a class using the Joshua Bloch Builder template, which is similar to this Pizza example:

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; } } 

but PMD reported 2 warnings:

  • (Points to the Builder.build () method) Avoid instantiating through private constructors from outside the constructor class. Activation through private constructors from outside the designer class often causes the creation of accessories. A factory method or detachment constructor can eliminate this situation. The generated class file is actually an interface. This gives the class access to invoke a new hidden area of ​​the constructor package, which takes an interface as an additional parameter. This turns a private designer effectively into one with a package scope and distinguish.
  • The class cannot be created and does not provide any static methods or fields. A class that has private constructors and does not have static methods or fields cannot be used.

Should I just ignore these warnings?

Another question: private fields in the Pizza and Builder classes are duplicated. This will be annoying when the number of private fields becomes larger. Is there any way to avoid this?

+4
source share
2 answers

About how to remove duplication.

I will get more downvotes :) But maybe something like this?

 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() { } } 
+2
source

Private fields in the Pizza and Builder classes are duplicated. This will be annoying when the number of private fields become larger. Is there any way to avoid this?

I personally get around this using the third private class of objects of static value, which contains all the fields and uses it both in the builder and in the main class (access to the field is processed by delegation). Of course, this can lead to bloating the count of the number of lines / classes, but it is invaluable if your builders are ultimately complicated by a large number of fields and checks.

In addition, it will not actually provide a static method for the Pizza class, which constructs a Pizza object with required fields. Unless, of course, you know what mandatory fields are, or are afraid that mandatory fields may change as your class evolves. If you think that as long as you can justify your actions after many thoughts (as Joshua Bloch does), you can safely ignore these warnings, knowing that you know what you are doing. :-)

Discarded fragment:

 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 } 
+1
source

All Articles