decorator
Attach new behaviour to objects at runtime by wrapping them in decorator objects.
SKILL.mdskills/code-quality/decorator/SKILL.md
GitHubDecorator
Wraps an object to extend its behaviour without modifying the original class or using inheritance. Decorators are composable — stack multiple wrappers for combined effects.
When to Use
- You need to add behaviour to individual objects without affecting others of the same class
- Extension by subclassing is impractical due to combinatorial explosion
- Behaviour should be composable and removable at runtime
- Cross-cutting concerns: logging, caching, validation, rate-limiting
How to Apply
- Define a
Componentinterface with the core operation - Create a
ConcreteComponentthat implementsComponent - Create a
BaseDecoratorimplementingComponentand holding a wrappedComponent - Create concrete decorators extending
BaseDecorator, adding behaviour before/after the delegate call - Wrap components with decorators at the composition root
Example
interface DataSource { write(data: string): void; read(): string; }
class FileDataSource implements DataSource {
constructor(private filename: string) {}
write(data: string) { /* write to file */ }
read(): string { return ''; /* read from file */ }
}
class EncryptionDecorator implements DataSource {
constructor(private wrapped: DataSource) {}
write(data: string) { this.wrapped.write(encrypt(data)); }
read(): string { return decrypt(this.wrapped.read()); }
}
class CompressionDecorator implements DataSource {
constructor(private wrapped: DataSource) {}
write(data: string) { this.wrapped.write(compress(data)); }
read(): string { return decompress(this.wrapped.read()); }
}
// Stack decorators
const source = new CompressionDecorator(new EncryptionDecorator(new FileDataSource('data.bin')));
source.write('hello');