0

I am trying to learn and implement Builder Pattern using a Pizza example.

I am trying to extend the solution I have to achieve 1 more thing:

Users should be able to order a specific Pizza ( Hawaiin, Meat, Veggie ) with a little bit of customization in it. Example --> In Meat Pizza --> Add Chicken + bacon

Looking for suggestions about implementing this in a cleaner way ( avoiding if-else )

Here is my Pizza and PizzaBuilder class:

public class Pizza {

  private String dough;
  private String sauce;
  private String toppings;

  public Pizza(PizzaBuilder pizzaBuilder) {
    this.dough = pizzaBuilder.dough;
    this.sauce = pizzaBuilder.sauce;
    this.toppings = pizzaBuilder.toppings;
  }

  public void setDough(String dough) {
    this.dough = dough;
  }

  public void setSauce(String sauce) {
    this.sauce = sauce;
  }

  public void setToppings(String toppings) {
    this.toppings = toppings;
  }

  abstract static class PizzaBuilder {
    private String dough;
    private String sauce;
    private String toppings;
    protected Pizza pizza;

    abstract void addDough();
    abstract void addSauce();
    abstract void addToppings();

    public PizzaBuilder addDough(String dough) {
      this.dough = dough;
      return this;
    }

    public PizzaBuilder addSauce(String sauce) {
      this.sauce = sauce;
      return this;
    }

    public PizzaBuilder addToppings(String toppings) {
      this.toppings = toppings;
      return this;
    }

    public Pizza bakeAPizza() {
      return pizza;
    }

    public PizzaBuilder makeAPizza() {
      getPizza();
      this.addDough();
      this.addSauce();
      this.addToppings();
      return this;
    }

    public PizzaBuilder getPizza() {
      pizza = new Pizza(this);
      return this;
    }
  }

  @Override
  public String toString() {
    return "Pizza{" + "dough='" + dough + '\'' + ", sauce='" + sauce + '\'' + ", toppings='" + toppings + '\'' + '}';
  }
}

Here is my MeatPizzaBuilder class:

public class MeatPizzaBuilder extends PizzaBuilder {

  @Override
  void addDough() {
    pizza.setDough("Italian Wheat");
  }

  @Override
  void addSauce() {
    pizza.setSauce("mustard");
  }

  @Override
  void addToppings() {
    pizza.setToppings("Meat");
  }
}

Similar to MeatPizzaBuilder: I have HawaainPizzaBuilder, VeggiePizzaBuilder and GenericPizzaBuilder. Here is my GenericPizzaBuilder class:

   public class GenericPizzaBuilder extends PizzaBuilder {

  @Override
  void addDough() {

  }

  @Override
  void addSauce() {

  }

  @Override
  void addToppings() {

  }
}

And Finally the PizzaShop ( main method )

public class PizzaShop {
    public static void main(String[] args) {

      Pizza hawaiinPizza = new HawaainPizzaBuilder().makeAPizza().bakeAPizza();
      Pizza meatPizza = new MeatPizzaBuilder().makeAPizza().bakeAPizza();
      Pizza veggiePizza = new VeggiePizzaBuilder().makeAPizza().bakeAPizza();
      Pizza genericPizza = new GenericPizzaBuilder()
          .addDough("Test")
          .addSauce("Test Sauce")
          .addToppings("All Veggeis minus Brocolli")
          .getPizza()
          .bakeAPizza();

      System.out.println("Here is your Hawaiin Pizza: "+ hawaiinPizza.toString());
      System.out.println("Here is your Meat Pizza: "+ meatPizza.toString());
      System.out.println("Here is your Veggie Pizza: "+ veggiePizza.toString());
      System.out.println("Here is your Generic Pizza: "+ genericPizza.toString());
    }
}

So the User should be able to say :

I want a Meat Pizza with Chicken

kukroid
  • 420
  • 6
  • 15
  • 1
    Not really an answer, but a few points. 1) You don't typically `extend` a `Builder` class to make your `Object` - e.g. `GenericPizza` and `MeatPizza` would instead `extend Pizza`. 2) From an OO perspective, I don't think `MeatPizza` and `GenericPizza` are different `Object`s, when you already store `toppings` as a field on `Pizza`. They are just `Pizza` `Object`s with a different `toppings` field. – BeUndead May 11 '21 at 23:12
  • @BeUndead Thank you for mentioning the `extend Builder` part. I should have named my class appropriately. It should have been `GenericPiizzaBuilder` || `HawaainPizzaBuilder`. The Only reason I am extending `Builder` is so that for these readymade PizzaBuilders I should not have to set any parameters. But now, I would like to give the user the functionality to modify any of the params as well. – kukroid May 12 '21 at 03:24
  • Like @BeUndead mentioned, by having to extend your `Builder` class to make standard types of pizza, you're missing the value of the builder itself. Think of the builder as the *cook* and the type of pizza as the *recipe*. When you have a different recipe, you don't hire a new cook, you tell the cook what to make! What are recipes in code? Subroutines! If you want to have a standard way of making a meat pizza, just have a method `makeMeatPizza` which calls your (generic) builder with the specific configuration you want. All of the no-arg methods you've added don't provide value. – Mark Peters May 12 '21 at 03:42
  • After playing around and understanding how the `Builder Pattern` works, I would suggest you check what `Lombok` can do for you. It can generate the methods and the boilerplate code for you, so that you get rid of the implementation, and take care only on the logic of your program :). [For more info.](https://www.baeldung.com/lombok-builder) – Renis1235 May 12 '21 at 07:34
  • @BeUndead, extending an abstract Builder is how the pattern is defined in the GoF book, and therefore in other sources that describe GoF patterns (Pizza comes from Head First Design). IMO the GoF pattern is over-engineered, and that's why, "You don't typically `extend` a `Builder`". But from a historical perspective, extending an abstract Builder is the canonical form of the pattern. The variations commonly seen today are improvements. [How to implement the Builder Design Pattern in the right way?](https://stackoverflow.com/q/66524505/1371329) – jaco0646 May 12 '21 at 12:56
  • @jaco0646: That’s not what I said, ‘.. to make your `Object`‘. Before the edit it was `MeatPizza extends PizzaBuilder` (with no relation to `Pizza`). – BeUndead May 12 '21 at 18:59

0 Answers0