Decorator Pattern

April 1, 2026

Decorator = "Dynamically add new behavior to an object without modifying its class." Wrapping the original object in a decorator class that implements the same interface

Example: SimpleCoffee, CoffeeDecorator, MilkDecorator, SugarDecorator.

// Component
interface Coffee {
    double cost();
}

// Concrete component
class SimpleCoffee implements Coffee {
    public double cost() {
        return 5;
    }
}

// Decorator base class
abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
}

// Concrete decorators
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    public double cost() {
        return coffee.cost() + 2;
    }
}

class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    public double cost() {
        return coffee.cost() + 1;
    }
}

How to use

Step 1: Create base object

Coffee coffee = new SimpleCoffee();
System.out.println(coffee.cost()); // 5

Step 2: Wrap with decorators

coffee = new MilkDecorator(coffee);   // add milk
coffee = new SugarDecorator(coffee);  // add sugar

System.out.println(coffee.cost()); // 5 + 2 + 1 = 8

Or you can

Coffee coffee = new SugarDecorator(
                    new MilkDecorator(
                        new SimpleCoffee()
                    )
                );

System.out.println(coffee.cost()); // 8

Real-world usage examples

InputStream input = new BufferedInputStream(
                        new FileInputStream("file.txt"));

  • Adapter: use a old class into another new class, when call new method then call old method of old class inside.
  • Factory Method:
  • Bridge pattern:
  • Composite pattern: File, Folder, List Interface