Card 03/ 08
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.
class Component(ABC):
@abstractmethod
def operation(self) -> str: ...Concrete component
The basic object, which knows nothing of decorators.
class ConcreteComponent(Component):
def operation(self) -> str:
return "ConcreteComponent"Decorator
Is a component, holds a component, and passes the call on.
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.
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.
print(DecoratorB(DecoratorA(plain)).operation())The complete template
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())ConcreteComponent
A(ConcreteComponent)
B(A(ConcreteComponent))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() + ")";
}
}ConcreteComponent
A(ConcreteComponent)
B(A(ConcreteComponent))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());ConcreteComponent
A(ConcreteComponent)
B(A(ConcreteComponent))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.
← → move through sections and cards