library
intermediateDecorator 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.