All topics
library
intermediate

Decorator Pattern & I/O Streams

Understand how Java I/O streams use the Decorator pattern and how to apply it in your own designs.

The Decorator pattern attaches additional behavior to an object dynamically by wrapping it. Java I/O streams are the textbook example:

Decorator = gift wrapping. The gift (core object) stays the same. Each wrapping layer (decorator) adds something: tissue paper (buffering), a bow (compression), a card (logging). You can combine any layers in any order.

Key Concepts

1
new BufferedInputStream(new GZIPInputStream(new FileInputStream("data.gz")))
2
Each wrapper adds functionality: - FileInputStream: reads raw bytes from a file - GZIPInputStream: adds decompression - BufferedInputStream: adds buffering
3
The pattern: 1. Component (interface/abstract class): InputStream 2. Concrete component: FileInputStream 3. Decorator (abstract): FilterInputStream 4. Concrete decorators: BufferedInputStream, GZIPInputStream, CipherInputStream
4
Decorator vs Inheritance: - Inheritance: behavior fixed at compile time, class explosion (BufferedGZIPFileInputStream?) - Decorator: compose behaviors at runtime, any combination
5
Applications beyond I/O: - Logging decorators: wrap a service to add logging - Caching decorators: wrap a repository to add caching - Retry decorators: wrap an HTTP client to add retry logic - Validation decorators: wrap input processing to add validation
6
Java I/O design is both the best illustration and the most common complaint about the pattern — the nesting can be verbose.