The full picture
| Pattern | In the wild | The force it resolves |
|---|---|---|
| Builder | HttpRequest.newBuilder()…build() | Many optional params, immutability at the end |
| Strategy | Comparator, RejectedExecutionHandler | Behavior varies independently of host |
| Decorator | new GZIPInputStream(new BufferedInputStream(in)) | Stackable capabilities without subclass explosion |
| Proxy | JDK dynamic proxy / CGLIB — @Transactional | Cross-cutting interception behind the same interface |
| Observer | ApplicationEvents, Flow API | Decoupled notification, N listeners |
| Template Method | AbstractStringBuilder, JdbcTemplate* | Fixed algorithm, variable steps (*JdbcTemplate is really Strategy-via-lambda) |
Anti-pattern signals a lead should call out: pattern-first design (interfaces + factories before a second implementation exists), Singleton-as-global-state (hidden coupling, test pain — DI containers made it obsolete), deep inheritance where Strategy/Decorator composition would do, and 'pattern name as documentation' where a lambda suffices. Post-Java 8, many GoF patterns compress dramatically: Strategy is a Function, Command is a Runnable, Observer is a listener lambda — the forces remain, the ceremony shouldn't.