Thursday, 2 January 2014

Decorator Design pattern - Implementation [Ice Cream]

🍦 Level Up Your Java & Design Pattern Skills!

Enjoying this practical tutorial? Subscribe to Ram N Java for clean code, object-oriented best practices, and detailed programming walkthroughs.

🔔 Subscribe to Ram N Java

What is the Decorator Design Pattern?

The Decorator Pattern is a structural design pattern that lets you dynamically attach new behaviors, responsibilities, or properties to an object at runtime without altering its original class structure.

Instead of subclassing (inheritance), which creates an overwhelming number of classes for every feature combination, the Decorator Pattern relies on composition—wrapping objects inside other decorator objects seamlessly.

The Real-World Scenario: Building Custom Ice Creams

Imagine ordering an ice cream. You start with a base Simple Ice Cream. From there, you might want to add toppings like:

  • Nuts
  • Honey
  • Chocolate Syrup

If you attempted to create subclasses for every single mix-and-match order (like IceCreamWithHoneyAndNuts, IceCreamWithNutsOnly, etc.), your codebase would quickly explode with dozens of redundant classes.

With the Decorator Pattern, each topping is a wrapper that decorates the base ice cream, calculates the updated cost, and adds description details dynamically!

Step-by-Step Code Walkthrough

1. Component Interface

Define the core interface that both base ice creams and decorators will share:

public interface Icecream {
    String makeIcecream();
}

2. Concrete Component

Provide a base implementation representing standard, un-decorated ice cream:

public class SimpleIcecream implements Icecream {
    @Override
    public String makeIcecream() {
        return "Base Ice Cream";
    }
}

3. Abstract Decorator

The decorator implements Icecream and maintains a reference to the wrapped Icecream object:

public abstract class IcecreamDecorator implements Icecream {
    protected Icecream specialIcecream;

    public IcecreamDecorator(Icecream specialIcecream) {
        this.specialIcecream = specialIcecream;
    }

    @Override
    public String makeIcecream() {
        return specialIcecream.makeIcecream();
    }
}

4. Concrete Decorators (Toppings)

Add specific toppings by extending the decorator and chaining the behavior:

public class NuttyDecorator extends IcecreamDecorator {
    public NuttyDecorator(Icecream specialIcecream) {
        super(specialIcecream);
    }

    @Override
    public String makeIcecream() {
        return specialIcecream.makeIcecream() + " + Crunchy Nuts";
    }
}

public class HoneyDecorator extends IcecreamDecorator {
    public HoneyDecorator(Icecream specialIcecream) {
        super(specialIcecream);
    }

    @Override
    public String makeIcecream() {
        return specialIcecream.makeIcecream() + " + Sweet Honey";
    }
}

5. Putting It All Together

public class TestDecorator {
    public static void main(String[] args) {
        Icecream myOrder = new HoneyDecorator(new NuttyDecorator(new SimpleIcecream()));
        System.out.println(myOrder.makeIcecream());
        // Output: Base Ice Cream + Crunchy Nuts + Sweet Honey
    }
}

Why Use the Decorator Pattern?

  • Open/Closed Principle: Add endless new toppings without modifying existing classes.
  • Dynamic Assembly: Stack and nest toppings arbitrarily at runtime.
  • Clean Architecture: Avoids monstrous class hierarchies.

Related Tutorials You Might Like

Enhance your software engineering toolkit with these related design pattern tutorials:


Click here to watch in Youtube : https://www.youtube.com/watch?v=-CSs47U8H4k

Click the below Image to Enlarge

Decorator Design pattern - Implementation [Ice Cream]


Decorator Design pattern - Implementation [Ice Cream] - Class Diagram

































Icecream.java

public interface Icecream
{
public String makeIcecream();
}

VanillaIcecream.java

public class VanillaIcecream implements Icecream
{

@Override
public String makeIcecream()
{
return "Vanilla Icecream";
}
}

IcecreamDecorator.java

abstract class IcecreamDecorator implements Icecream
{

protected Icecream specialVanillaIcecream;

public IcecreamDecorator( Icecream specialVanillaIcecream )
{
this.specialVanillaIcecream = specialVanillaIcecream;
}

public String makeIcecream()
{
return specialVanillaIcecream.makeIcecream();
}
}

ChocolateDecorator.java

public class ChocolateDecorator extends IcecreamDecorator
{

public ChocolateDecorator( Icecream specialIcecream )
{
super(specialIcecream);
}

public String makeIcecream()
{
return specialVanillaIcecream.makeIcecream() + addChocolate();
}

private String addChocolate()
{
return " + with chocolate";
}
}

NuttyDecorator.java

public class NuttyDecorator extends IcecreamDecorator
{

public NuttyDecorator( Icecream specialVanillaIcecream )
{
super(specialVanillaIcecream);
}

public String makeIcecream()
{
return specialVanillaIcecream.makeIcecream() + addNuts();
}

private String addNuts()
{
return " + with nuts";
}
}

DecoratorClient.java

public class DecoratorClient
{

public static void main( String args[] )
{
VanillaIcecream vanillaIcecreamObj = new VanillaIcecream();
String vanillaIcecream = vanillaIcecreamObj.makeIcecream();
System.out.println(vanillaIcecream);
String vanillaIcecreamWithNuts=new NuttyDecorator(vanillaIcecreamObj).makeIcecream();
System.out.println("\n'"+vanillaIcecreamWithNuts + "' is prepared using NuttyDecorator");
String vanillaIcecreamWithChocalate=new ChocolateDecorator(vanillaIcecreamObj).makeIcecream();
System.out.println("\n'"+vanillaIcecreamWithChocalate+ "' is prepared using ChocolateDecorator");
String vanillaIcecreamWithChocalateAndNuts=new NuttyDecorator(new ChocolateDecorator(vanillaIcecreamObj)).makeIcecream();
System.out.println("\n'"+vanillaIcecreamWithChocalateAndNuts+ "' is prepared using ChocolateDecorator and NuttyDecorator");
}

}

Output

Vanilla Icecream

'Vanilla Icecream + with nuts' is prepared using NuttyDecorator

'Vanilla Icecream + with chocolate' is prepared using ChocolateDecorator

'Vanilla Icecream + with chocolate + with nuts' is prepared using ChocolateDecorator and NuttyDecorator


See also:

  • Decorator Design pattern - Introduction
  • Decorator Design pattern - Real Time Example [Dosa]
  • Decorator Design pattern - Real Time Example [Ice Cream]
  • Decorator Design pattern - Real Time Example [Pizza]
  • Decorator Design pattern - Real Time Example [Car]
  • Decorator Design pattern - Class Diagram
  • Decorator Design pattern - Sequence Diagram
  • Decorator Design pattern - Implementation [Dosa]
  • Decorator Design pattern - Implementation [Pizza]
  • Decorator Design pattern - Implementation [Car]
  • Decorator Design pattern - Implementation [Shape]
  • Decorator Design pattern - Key Points
  • All Design Patterns Links
  • No comments:

    Post a Comment

    Tutorials