Design Patterns in Java
Creational, structural, and behavioural patterns with Java code examples
Design patterns are reusable solutions to common software design problems. The Gang of Four (GoF) catalogue defines 23 patterns in three categories: Creational (how objects are created), Structural (how objects are composed), and Behavioral (how objects communicate). Knowing when to apply — and when not to apply — a pattern is a mark of seniority.
Key Points
- Singleton: one instance per JVM — use enum Singleton for thread-safety without double-checked locking
- Factory Method: subclasses decide which class to instantiate — decouples creation from use
- Builder: construct complex objects step by step — avoids telescoping constructors; Lombok @Builder generates it
- Adapter: wraps incompatible interface — converts one interface to another without modifying source
- Decorator: adds behaviour dynamically — wraps an object and adds responsibility; Java I/O streams are textbook decorators
- Proxy: controls access to an object — lazy init, logging, security; Spring AOP and JDK dynamic proxies
- Observer: one-to-many dependency — when object changes, all dependents notified; EventListener, RxJava, Spring events
- Strategy: define a family of algorithms, make them interchangeable — eliminates conditionals; Comparator is a strategy
- Template Method: skeleton algorithm in base class, details in subclasses — Spring's JdbcTemplate, RestTemplate follow this
| Pattern | Category | Java Example | Problem solved |
|---|---|---|---|
| Singleton | Creational | Runtime.getRuntime() | One shared instance |
| Factory Method | Creational | Calendar.getInstance() | Decouple creation |
| Builder | Creational | StringBuilder, Lombok @Builder | Complex object construction |
| Adapter | Structural | Arrays.asList(), InputStreamReader | Interface mismatch |
| Decorator | Structural | BufferedInputStream(FileInputStream) | Add behaviour dynamically |
| Proxy | Structural | Spring @Transactional, Mockito mocks | Control access / AOP |
| Observer | Behavioral | EventListener, RxJava, Spring events | Decouple publisher/subscriber |
| Strategy | Behavioral | Comparator, Collections.sort() | Interchangeable algorithms |
| Template Method | Behavioral | JdbcTemplate, AbstractList | Skeleton with pluggable steps |
Design patterns in Java: enum Singleton, Builder, Strategy, Spring Observer, I/O Decorator
// Singleton — enum is the safest approach (thread-safe, serialization-safe)
public enum DatabaseConnection {
INSTANCE;
private final Connection conn = createConnection();
public Connection get() { return conn; }
}
// Builder — fluent API
Person person = new Person.Builder("Alice")
.age(30).email("alice@example.com").city("London").build();
// Strategy — swap algorithms at runtime
interface SortStrategy { void sort(int[] arr); }
class QuickSort implements SortStrategy { ... }
class MergeSort implements SortStrategy { ... }
class Sorter {
private SortStrategy strategy;
Sorter(SortStrategy s) { this.strategy = s; }
void sort(int[] arr) { strategy.sort(arr); }
}
// Observer — Spring application events
@Component class OrderService {
@Autowired ApplicationEventPublisher publisher;
void placeOrder(Order o) {
// ... save order
publisher.publishEvent(new OrderPlacedEvent(o));
}
}
@Component class EmailService {
@EventListener void handle(OrderPlacedEvent e) { sendEmail(e.order()); }
}
// Decorator — I/O streams
InputStream in = new GZIPInputStream(
new BufferedInputStream(
new FileInputStream("data.gz")));Real-World Example
Spring Framework is a living catalogue of design patterns: IoC container (Dependency Injection), AOP (Proxy + Decorator), JdbcTemplate (Template Method), ApplicationEvent (Observer), FactoryBean (Factory). Knowing the pattern behind a framework feature helps you configure and debug it correctly.