jan
jan

Reputation: 53

java builder pattern and changing field

Im having difficulties to figure out how to change some field in a object created by builder pattern: for example this is the class

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

and Pizza obect is created like this:

Pizza pizza = new Pizza.Builder(12)
                       .cheese(true)
                       .pepperoni(true)
                       .bacon(true)
                       .build();

now what I'm trying to find out is how to change in this object for example cheese field to false? I don't have getters and setters, I know I can use reflection but it makes code harder to read and understand. So is builder pattern useful to not final objects ?

Upvotes: 1

Views: 13441

Answers (4)

Max
Max

Reputation: 774

The best way is to use Lombok's @Builder annotation. And you need to specify (toBuilder = true) to be able to convert the object back to the builder and modify the field.

@Builder(toBuilder = true)
public class Pizza {
 ...
}

So, you've created the Pizza
Pizza pizza = Pizza.builder()
                   .cheese(true)
                   .pepperoni(true)
                   .bacon(true)
                   .build();

And now you want to modify one field - super easy!

Pizza modifiedPizza = pizza.toBuilder()
                           .cheese(false)
                           .build();

Upvotes: 2

Adya
Adya

Reputation: 1112

Builder class should have methods to set the optional parameters and it should return the same Builder object after setting the optional attribute. As "cheese" is your optional parameter so you need a setter for it in your Builder class

public Builder cheese(Boolean cheese) {
            this.cheese = cheese;
            return this;
        }

Then you can use :

Pizza pizza1 = new Pizza.Builder(12)
                       .cheese(false)
                       .pepperoni(true)
                       .bacon(true)
                       .build();

Upvotes: 0

Hearen
Hearen

Reputation: 7828

how to change in this object for example cheese field to false?

You should add a setter to the Pizza as:

class Pizza {
    //...

    public void setCheese(boolean cheese) {
        this.cheese = cheese;
    }

    @Override
    public String toString() {
        return String.format("cheese: %s", this.cheese);
    }
    //...
}

And then you can use it as:

    System.out.println(pizza);
    pizza.setCheese(false);
    System.out.println(pizza);

After your initialization, the output:

cheese: true
cheese: false

So is builder pattern useful to not final objects ?

There are some interesting posts discussing Builder Pattern: Three Reasons Why I Like the Builder Pattern and When would you use the Builder Pattern?.

Personally, I would say it quite depends on your case itself.

Upvotes: 3

Michael
Michael

Reputation: 2683

The builder pattern is usually good to create immutable objects but it does not need to do so. If you'd like to be able to change values after build, you just need to add a setter for that.

Upvotes: 4

Related Questions