You need to add responsibilities to an object dynamically without modifying the original class. Subclassing every combination is explosive (BaseLogger + TimestampLogger + JSONLogger + EncryptionLogger = 2^N classes). Decorator wraps the original and adds behavior transparently.
// ─── EXAMPLE 1 ──────────────────────────────────────────────────────────────
// WHAT WE ARE IMPLEMENTING:
// A database stream writer wrapping files with Compression and Encryption
// layers at runtime.
//
// WHERE THE DECORATOR FITS IN:
// DataStream is the Component. FileDataStream is the Concrete Component.
// DataStreamDecorator is the base Decorator class wrapped by
// EncryptionDecorator.
// ────────────────────────────────────────────────────────────────────────────
// --- Component ---
interface Logger {
void log(String message);
}
// --- Concrete component ---
class SimpleLogger implements Logger {
public void log(String message) {
System.out.println(message);
}
}
// --- Base decorator ---
abstract class LoggerDecorator implements Logger {
protected final Logger wrapped;
public LoggerDecorator(Logger wrapped) { this.wrapped = wrapped; }
public void log(String message) {
wrapped.log(message); // Default: delegate
}
}
// --- Concrete decorators ---
class TimestampDecorator extends LoggerDecorator {
public TimestampDecorator(Logger wrapped) { super(wrapped); }
public void log(String message) {
super.log("[2025-01-15 10:30:00] " + message);
}
}
class JsonDecorator extends LoggerDecorator {
public JsonDecorator(Logger wrapped) { super(wrapped); }
public void log(String message) {
super.log("{"message": "" + message + "", "level": "INFO"}");
}
}
class EncryptionDecorator extends LoggerDecorator {
public EncryptionDecorator(Logger wrapped) { super(wrapped); }
public void log(String message) {
String encrypted = "encrypted(" + message + ")";
super.log(encrypted);
}
}
public class Main {
public static void main(String[] args) {
// Compose decorators at runtime
Logger logger = new TimestampDecorator(
new JsonDecorator(
new EncryptionDecorator(
new SimpleLogger())));
logger.log("User login successful");
// Output: [2025-01-15 10:30:00] {"message": "encrypted(User login successful)", "level": "INFO"}
}
}