Card 03/ 08

CodeDifficulty: Intermediate3 min

Decorator Template in Python, Java and TypeScript

One component, two decorators, and a stack of both.

The Decorator template is the pattern in its pure form, with the participant names from the class diagram. Each decorator wraps the result of the call it passes on in its own letter, so the output shows how a call travels through the stack. The steps add each participant in Python, and the tabs give the complete program in three languages, each with its output.

Building the template one participant at a time

Component

The interface every object in a stack shares.

py
class Component(ABC):
    @abstractmethod
    def operation(self) -> str: ...

Concrete component

The basic object, which knows nothing of decorators.

py
class ConcreteComponent(Component):
    def operation(self) -> str:
        return "ConcreteComponent"

Decorator

Is a component, holds a component, and passes the call on.

py
class Decorator(Component):
    def __init__(self, component: Component) -> None:
        self._component = component

    def operation(self) -> str:
        return self._component.operation()

Concrete decorators

Each adds its own work around the call it passes on.

py
class DecoratorA(Decorator):
    def operation(self) -> str:
        return f"A({super().operation()})"

Client

Builds a stack from the inside out and calls the outermost object.

py
print(DecoratorB(DecoratorA(plain)).operation())

The complete template

py
from abc import ABC, abstractmethod


class Component(ABC):
    @abstractmethod
    def operation(self) -> str: ...


class ConcreteComponent(Component):
    def operation(self) -> str:
        return "ConcreteComponent"


class Decorator(Component):
    def __init__(self, component: Component) -> None:
        self._component = component

    def operation(self) -> str:
        return self._component.operation()


class DecoratorA(Decorator):
    def operation(self) -> str:
        return f"A({super().operation()})"


class DecoratorB(Decorator):
    def operation(self) -> str:
        return f"B({super().operation()})"


plain = ConcreteComponent()
print(plain.operation())
print(DecoratorA(plain).operation())
print(DecoratorB(DecoratorA(plain)).operation())
OutputRan with python:3.12-slim (Python 3.12.13)
ConcreteComponent
A(ConcreteComponent)
B(A(ConcreteComponent))
The base decorator holds a component and passes the call on; each concrete decorator wraps the result.
java
public class DeTemplate {
    public static void main(String[] args) {
        Component plain = new ConcreteComponent();
        System.out.println(plain.operation());
        System.out.println(new DecoratorA(plain).operation());
        System.out.println(new DecoratorB(new DecoratorA(plain)).operation());
    }
}

interface Component {
    String operation();
}

class ConcreteComponent implements Component {
    public String operation() {
        return "ConcreteComponent";
    }
}

abstract class Decorator implements Component {
    protected final Component component;

    Decorator(Component component) {
        this.component = component;
    }

    public String operation() {
        return component.operation();
    }
}

class DecoratorA extends Decorator {
    DecoratorA(Component component) {
        super(component);
    }

    public String operation() {
        return "A(" + super.operation() + ")";
    }
}

class DecoratorB extends Decorator {
    DecoratorB(Component component) {
        super(component);
    }

    public String operation() {
        return "B(" + super.operation() + ")";
    }
}
OutputRan with eclipse-temurin:21-jdk (Java 21.0.12)
ConcreteComponent
A(ConcreteComponent)
B(A(ConcreteComponent))
Java places the client first so the source launcher finds `main`; the roles are the same.
ts
interface Component {
  operation(): string;
}

class ConcreteComponent implements Component {
  operation(): string {
    return "ConcreteComponent";
  }
}

abstract class Decorator implements Component {
  constructor(protected readonly component: Component) {}

  operation(): string {
    return this.component.operation();
  }
}

class DecoratorA extends Decorator {
  operation(): string {
    return `A(${super.operation()})`;
  }
}

class DecoratorB extends Decorator {
  operation(): string {
    return `B(${super.operation()})`;
  }
}

const plain: Component = new ConcreteComponent();
console.log(plain.operation());
console.log(new DecoratorA(plain).operation());
console.log(new DecoratorB(new DecoratorA(plain)).operation());
OutputRan with node:22-slim (Node 22.23.1), TypeScript 5.9.3
ConcreteComponent
A(ConcreteComponent)
B(A(ConcreteComponent))
A protected parameter property gives each subclass the wrapped component.

The last line of each output is B(A(ConcreteComponent)). The call enters at DecoratorB, the outermost object, which passes it to DecoratorA, which passes it to the concrete component. The results then return outwards, and each decorator wraps what it receives, so the decorator applied last is the outermost in the result. The order of any stack is decided on this return journey.