Decorator Design Pattern: Implementation in Java

The Code Bean
3 min readOct 6, 2023

--

Decorator Design Pattern | The Code Bean

The Decorator pattern is a structural design pattern that allows you to enhance or modify the behavior of objects at runtime. It achieves this by creating a set of decorator classes that are used to wrap concrete components. Each decorator adds a specific feature or behavior to the component, and you can stack multiple decorators to create various combinations.

When to Use the Decorator Pattern

You should consider using the Decorator pattern in the following scenarios:

  1. Adding New Features: You want to add extra features to objects without changing their core structure. It’s like putting toppings on a pizza without changing the pizza itself.
  2. Avoiding Messy Code: You want to avoid having too many different classes for all possible combinations of features. Instead, you can mix and match decorators as needed.
  3. Open for Extension, Closed for Modification: You want to make your code ready for future changes by allowing new features to be added without messing up existing code. This aligns with the Open/Closed Principle.

Implementing the Decorator Pattern in Java

Let’s illustrate the Decorator pattern with a fun example involving pizza. We’ll start with a simple pizza and use decorators to add various toppings to it.

Step 1: Create the Component Interface

// Component Interface
interface Pizza {
String getDescription();
double getCost();
}

Step 2: Implement the Concrete Component

// Concrete Component
class PlainPizza implements Pizza {
@Override
public String getDescription() {
return "Plain Pizza";
}

@Override
public double getCost() {
return 5.0;
}
}

Step 3: Develop the Decorator

// Decorator
abstract class PizzaDecorator implements Pizza {
protected Pizza decoratedPizza;

public PizzaDecorator(Pizza pizza) {
this.decoratedPizza = pizza;
}
}

Step 4: Create Concrete Decorators

// Concrete Decorators
class CheeseDecorator extends PizzaDecorator {
public CheeseDecorator(Pizza pizza) {
super(pizza);
}

@Override
public String getDescription() {
return decoratedPizza.getDescription() + ", Cheese";
}

@Override
public double getCost() {
return decoratedPizza.getCost() + 1.5;
}
}

class PepperoniDecorator extends PizzaDecorator {
public PepperoniDecorator(Pizza pizza) {
super(pizza);
}

@Override
public String getDescription() {
return decoratedPizza.getDescription() + ", Pepperoni";
}

@Override
public double getCost() {
return decoratedPizza.getCost() + 2.0;
}
}

Step 5: Using the Decorators

public class DecoratorMain {
public static void main(String[] args) {
// Create a plain pizza
Pizza pizza = new PlainPizza();

// Decorate the pizza with cheese and pepperoni
pizza = new CheeseDecorator(pizza);
pizza = new PepperoniDecorator(pizza);

// Get the description and cost of the decorated pizza
System.out.println("Description: " + pizza.getDescription());
System.out.println("Cost: $" + pizza.getCost());
}
}

In this example, we have a Pizza interface, a PlainPizza concrete component, and two decorators: CheeseDecorator and PepperoniDecorator. These decorators add cheese and pepperoni to the pizza while keeping the core PlainPizza class unchanged.

Conclusion

The Decorator pattern is a versatile tool for building flexible and extensible systems. It allows you to enhance the behavior of objects dynamically, making your code more maintainable and adaptable to changing requirements. By using this pattern, you can create complex combinations of features without the need for a convoluted class hierarchy.

--

--

The Code Bean

Tech enthusiasts community sharing knowledge on coding, software design, and web development. 🚀