Here are some of the most commonly used design patterns in Java, especially in Spring Boot projects, along with real-world examples:
1. Singleton Pattern
Purpose: Ensure only one instance of a class exists.
Use case: Spring-managed beans (@Component, @Service) by default are Singletons.
@Component
public class AppConfig {
// only one instance in the Spring context
}
2. Factory Pattern
Purpose: Create objects without exposing creation logic.
Use case: SessionFactory in Hibernate, DocumentBuilderFactory, or creating different NotificationService instances.
public class NotificationFactory {
public Notification getNotification(String type) {
if ("email".equals(type)) return new EmailNotification();
if ("sms".equals(type)) return new SMSNotification();
return null;
}
}
3. Builder Pattern
Purpose: Build complex objects step by step.
Use case: Creating ResponseEntity, or building custom DTOs in layers.
User user = User.builder()
.name("Alice")
.age(30)
.email("a@x.com")
.build();
4. Prototype Pattern
Purpose: Create a new object by copying an existing one.
Use case: Cloning a template configuration, or in Spring when you define @Scope("prototype").
@Component
@Scope("prototype")
public class TemporaryFileHandler { ... }
5. Adapter Pattern
Purpose: Allows incompatible interfaces to work together.
Use case: Integrating third-party APIs in Spring Boot using RestTemplate or WebClient.
public class LegacySystemAdapter implements NewSystemInterface {
private LegacySystem legacy;
public String fetchData() {
return legacy.getDataLegacy(); // adapts method name
}
}
6. Decorator Pattern
Purpose: Add new behavior to objects dynamically.
Use case: Spring’s OncePerRequestFilter or interceptors decorating HTTP requests/responses.
@Component
public class LoggingFilter extends OncePerRequestFilter {
protected void doFilterInternal(...) {
// log request details
filterChain.doFilter(request, response);
}
}
7. Observer Pattern
Purpose: One object notifies many others of changes.
Use case: Spring’s event system (ApplicationEventPublisher)
@Component
public class OrderService {
@Autowired ApplicationEventPublisher publisher;
public void placeOrder(Order order) {
// logic...
publisher.publishEvent(new OrderPlacedEvent(order));
}
}
8. Strategy Pattern
Purpose: Select algorithm at runtime.
Use case: Payment methods (card, PayPal), sorting algorithms, Spring Security password encoders.
public interface PaymentStrategy {
void pay(int amount);
}
public class CardPayment implements PaymentStrategy { ... }
public class PayPalPayment implements PaymentStrategy { ... }
9. Template Method Pattern
Purpose: Define a skeleton of an algorithm, subclasses fill in the steps.
Use case: JdbcTemplate, RestTemplate, and AbstractController
public abstract class ReportGenerator {
public void generateReport() {
fetchData();
process();
export();
}
abstract void fetchData();
abstract void process();
abstract void export();
}
10. Proxy Pattern
Purpose: Control access to another object (add extra functionality like logging, security)
Use case: Spring AOP, Hibernate lazy loading, transaction proxy
@Around("execution(* com.service.*.*(..))")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Before method: " + joinPoint.getSignature());
Object result = joinPoint.proceed();
System.out.println("After method");
return result;
}
Summary Table
| Pattern | Used For | Real-Time Example in Spring |
|---|---|---|
| Singleton | One shared instance | @Component, @Service |
| Factory | Centralized object creation | SessionFactory |
| Builder | Step-by-step object creation | Lombok @Builder, DTOs |
| Prototype | New instance every time | @Scope("prototype") |
| Adapter | Integrating incompatible APIs | REST API wrappers |
| Decorator | Add extra behavior | Servlet filters, logging |
| Observer | Publish/subscribe | Spring Events |
| Strategy | Dynamic behavior selection | Payment services |
| Template Method | Reusable skeleton methods | JdbcTemplate, RestTemplate |
| Proxy | Intercept method calls | AOP, Logging, Transactions |

Comments
Post a Comment