JavaRush /Java Blog /Random EN /Pizzeria problems. Builder vs Decorator.
CynepHy6
Level 34
Великий Новгород

Pizzeria problems. Builder vs Decorator.

Published in the Random EN group

Description of the problem.

We need to write a program. For a pizzeria that wants to prepare different types of pizza: Chicken, American, Meat, Hawaiian, Pepperoni, etc. Let's see which template and under which scenario is suitable for solving this problem. Traditionally, the Builder template is used to solve “pizza problems.” There are also examples of using the Decorator pattern, both patterns are correct, but there are differences in use. The Builder is a template for creating objects, while the Decorator is used to modify the finished object on the fly. Let's try to understand this with examples:

1. Template Builder:

In this case, the pizza is prepared with all the ingredients at once.
Pizza class:
public class Pizza{ private float totalPrice = 0; private Size size; private Topping topping; private Crust crust; private Cheese cheese; public Size getSize(){ return size; } public void setSize(Size size){ this.size = size; } public Topping getTopping(){ return topping; } public void setTopping(Topping topping){ this.topping = topping; } public Crust getCrust(){ return crust; } public void setCrust(Crust crust){ this.crust = crust; } public Cheese getCheese(){ return cheese; } public void setCheese(Cheese cheese){ this.cheese = cheese; } public float getTotalPrice(){ return totalPrice; } public void addToPrice(float price){ this.totalPrice = totalPrice + price; } }
4 enum classes:
public enum Cheese { AMERICAN{ public float getCost(){ return 40; } }, ITALIAN { public float getCost(){ return 60; } }; public abstract float getCost(); } public enum Crust { THIN{ public float getCost(){ return 70; } } , STUFFED{ public float getCost(){ return 90; } }; public abstract float getCost(); } public enum Size { MEDIUM { public float getCost() { return 100; } }, LARGE { public float getCost() { return 160; } }; public abstract float getCost(); } public enum Topping { PEPPERONI { public float getCost(){ return 30; } }, CHICKEN{ public float getCost(){ return 35; } }, MUSHROOM{ public float getCost(){ return 20; } }; public abstract float getCost(); }
PizzaBuilder class:
public class PizzaBuilder { Pizza pizza = new Pizza(); public PizzaBuilder withTopping(Topping topping) { pizza.setTopping(topping); pizza.addToPrice(topping.getCost()); return this; } public PizzaBuilder withSize(Size size) { pizza.setSize(size); pizza.addToPrice(size.getCost()); return this; } public PizzaBuilder withCrust(Crust crust) { pizza.setCrust(crust); pizza.addToPrice(crust.getCost()); return this; } public Pizza build() { return pizza; } public double calculatePrice() { return pizza.getTotalPrice(); } }
Class test:
public class PizzaBuilderTest { @Test public void shouldBuildThinCrustChickenPizza(){ Pizza pizza = new PizzaBuilder().withCrust(Crust.THIN).withTopping(Topping.CHICKEN).withSize(Size.LARGE).build(); assertEquals(Topping.CHICKEN,pizza.getTopping()); assertEquals(Size.LARGE,pizza.getSize()); assertEquals(Crust.THIN,pizza.getCrust()); assertEquals(265.0,pizza.getTotalPrice(),0); } }

2. Decorator Template:

The Decorator pattern is used to add or remove additional functionality to an object dynamically without affecting the original object. Used when some pizza base is prepared first and then various ingredients are added. Here we need an interface (Pizza) for BasePizza (the fundamental component) that we want to decorate and a PizzaDecorator class that actually implements the interface.
Pizza interface:
public interface Pizza { public String bakePizza(); public float getCost(); }
Implementation in BasePizza:
public class BasePizza implements Pizza{ public String bakePizza() { return "Basic Pizza"; } public float getCost(){ return 100; } }
PizzaDecorator class:
public class PizzaDecorator implements Pizza { Pizza pizza; public PizzaDecorator(Pizza newPizza) { this.pizza = newPizza; } public String bakePizza() { return pizza.bakePizza(); } @Override public float getCost() { return pizza.getCost(); } }
2 decorators: Mushroom and Pepperoni
public class Mushroom extends PizzaDecorator { public Mushroom(Pizza newPizza) { super(newPizza); } @Override public String bakePizza() { return super.bakePizza() + " with Mushroom Topings"; } @Override public float getCost() { return super.getCost()+80; } } public class Pepperoni extends PizzaDecorator { public Pepperoni(Pizza newPizza) { super(newPizza); } @Override public String bakePizza() { return super.bakePizza() + " with Pepperoni Toppings"; } @Override public float getCost() { return super.getCost()+110; } }
Class test:
public class PizzaDecoratorTest { @Test public void shouldMakePepperoniPizza(){ Pizza pizza = new Pepperoni(new BasePizza()); assertEquals("Basic Pizza with Pepperoni Toppings",pizza.bakePizza()); assertEquals(210.0,pizza.getCost(),0); } }

Differences

Patterns such as Builder and Factory (and Abstract Factory) are used in the creation of new objects. And patterns such as Decorator (also known as Structural Design Patterns) are used for extensibility or to provide structural changes to already created objects. Both types of patterns primarily promote composition through inheritance, and the differences are not significant enough to warrant using a Builder instead of a Decorator. Both give their own behavior when executed, rather than inheriting it. In one case it is better to use the Builder - if we want to limit the creation of objects with certain properties/functions. For example, there are 4-5 attributes that must be set before creating an object, or we want to freeze the creation of an object until certain attributes are set yet. Simply put, use it instead of a constructor - as Joshua Bloch writes in Java: Effective Programming, 2nd ed. The builder provides the attributes that the generated object should have but hides how to set them. A decorator is used to add new properties to an existing object when creating a new object based on it. There are no restrictions on freezing an object while all its features are being added. Both templates use composition and may look similar. The main difference is in their use.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION