Design patterns are standard solutions to common software design problems.
They are like templates you can use in different situations to write flexible, reusable, and maintainable code.
Java design patterns are categorized into three main types:
📌 Summary Diagram
Design Patterns
├── Creational (object creation mechanisms)
│ ├── Singleton
│ ├── Factory Method
│ ├── Abstract Factory
│ ├── Builder
│ └── Prototype
├── Structural (Class and object composition)
│ ├── Adapter
│ ├── Bridge
│ ├── Composite
│ ├── Decorator
│ ├── Facade
│ ├── Flyweight
│ └── Proxy
└── Behavioral (Communication between objects)
├── Chain of Responsibility
├── Command
├── Interpreter
├── Iterator
├── Mediator
├── Memento
├── Observer
├── State
├── Strategy
├── Template Method
└── Visitor
✅ 1. Creational Design Patterns
These patterns deal with object creation mechanisms, trying to create objects in a manner suitable to the situation.
🔹 a. Singleton Pattern
The Singleton Pattern is a creational design pattern that ensures a class has only one instance throughout the application lifecycle and provides a global point of access to that instance. This pattern is often used for managing shared resources like configuration objects, logging, or database connections.
Use When: You need to control access to shared resources (e.g., configuration, logging).
🔹 b. Factory Pattern
Definition: The Factory Pattern is a creational design pattern that provides a way to create objects without exposing the creation logic to the client. Instead of using new
, you call a factory method to get an object.
Factory Design Pattern is a creational pattern that provides an interface or method to create objects in a superclass, but allows subclasses or the factory method to decide which class to instantiate.
Use When: You have a superclass with multiple subclasses and need to return one of the subclasses based on input.
interface Shape {
void draw();
}
// Concrete implementations
class Circle implements Shape {
public void draw() {
System.out.println("Drawing Circle");
}
}
class Square implements Shape {
public void draw() {
System.out.println("Drawing Square");
}
}
// Factory class
class ShapeFactory {
public static Shape getShape(String type) {
if ("CIRCLE".equalsIgnoreCase(type)) {
return new Circle();
} else if ("SQUARE".equalsIgnoreCase(type)) {
return new Square();
}
throw new IllegalArgumentException("Unsupported Shape: " + type);
}
}
// Usage
public class FactoryPattern {
public static void main(String[] args) {
Shape shape = ShapeFactory.getShape("circle");
shape.draw(); // Output: Drawing Circle
Shape shape1 = ShapeFactory.getShape("Square");
shape1.draw(); // Output: Drawing Square
}
}
🔹 c. Abstract Factory Pattern
Definition: Factory of factories. It provides an interface for creating families of related objects without specifying concrete classes.
Use When: You want to create related objects without knowing their concrete classes.
🔹 d. Builder Pattern
Definition: The Builder Pattern is a creational design pattern used to construct complex objects step by step, especially when an object has many optional parameters. It helps create immutable objects with better readability and flexibility.
Use When: You want to construct complex objects in a readable and controlled manner.
🔹 e. Prototype Pattern
Definition: The Prototype Pattern is a creational design pattern that lets you create a copy (clone) of an existing object, instead of creating a new one from scratch.
Use When: Object creation is costly.
✅ 2. Structural Design Patterns
These patterns deal with object composition, helping ensure classes work together properly.
🔹 a. Adapter Pattern
Definition: The Adapter Pattern is a structural design pattern that allows incompatible interfaces to work together. It acts as a bridge between two different interfaces by converting one into another.
Use When: You want to use an existing class but its interface does not match your requirements.
🔹 b. Decorator Pattern
Definition: The Decorator Pattern is a structural design pattern that allows you to add new behavior or functionality to an object dynamically, without changing its structure or code.
Use When: You want to add new functionality without altering existing code.
Follows Open/Closed Principle: Open for extension, closed for modification.
🔹 c. Facade Pattern
Definition: The Facade Pattern is a structural design pattern that provides a simplified interface to a complex system of classes, libraries, or frameworks. It hides the complexities and exposes only what is necessary to the client.
✅ 3. Behavioral Design Patterns
These focus on communication between objects.
🔹 a. Observer Pattern
Definition: The Observer Pattern is a behavioral design pattern where an object (called Subject) maintains a list of observers and notifies them automatically of any state changes. One-to-many dependency between objects. If one changes, all dependents are notified.
Use When: Implement event handling systems.
🔹 b. Strategy Pattern
Definition: The Strategy Pattern is a behavioral design pattern that allows you to define a family of algorithms, put each in a separate class, and switch between them at runtime without changing the client code.
Use When: You want to change behavior dynamically.
🔹 c. Command Pattern
Definition: Encapsulate a request as an object.
The Command Pattern is a behavioral design pattern that turns a request into an object, allowing you to parameterize methods with different requests, queue them, or log them. It also supports undo/redo operations.
4. Microservices-Specific Design Patterns
(a a) API Gateway Pattern
U Used in: Centralizing requests in microservices architecture (Spring Cloud Gateway)
@ Configuration p public class ApiGatewayConfig { @Bean public RouteLocator routes(RouteLocatorBuilder builder) { return builder.routes() .route("user-service", r -> r.path("/users/**").uri("lb://USER-SERVICE")) .route("order-service", r -> r.path("/orders/**").uri("lb://ORDER-SERVICE")) .build(); } } @ Configuration p public class ApiGatewayConfig { @Bean public RouteLocator routes(RouteLocatorBuilder builder) { return builder.routes() .route("user-service", r -> r.path("/users/**").uri("lb://USER-SERVICE")) .route("order-service", r -> r.path("/orders/**").uri("lb://ORDER-SERVICE")) .build(); } } b) Circuit Breaker Pattern U Used in: Fault tolerance (Resilience4j, Hystrix) @RestController p public class PaymentController { @Autowired private PaymentService paymentService;
@GetMapping("/pay") @CircuitBreaker(name = "paymentService", fallbackMethod = "fallbackPayment") public String processPayment() { return paymentService.pay(); }
public String fallbackPayment(Exception e) { return "Payment Service is currently unavailable."; } }
C Conclusion
In my Spring Boot project, these design patterns help improve:
- Scalability (e.g., Microservices patterns like API Gateway, Circuit Breaker)
- Code reusability (e.g., Template Method, Strategy Pattern)
- Maintainability (e.g., Singleton, Factory, Proxy)
- Extensibility (e.g., Observer, Decorator)
✅ Summary Table
Pattern | Category | Purpose |
---|---|---|
Singleton | Creational | One instance, global access |
Factory | Creational | Creates object based on input |
Abstract Factory | Creational | Creates related families of objects |
Builder | Creational | Step-by-step object construction |
Prototype | Creational | Clone existing object |
Adapter | Structural | Converts one interface to another |
Decorator | Structural | Adds behavior dynamically |
Facade | Structural | Simplifies subsystem access |
Observer | Behavioral | Publish-subscribe model |
Strategy | Behavioral | Choose algorithm at runtime |
Command | Behavioral | Encapsulate actions as objects |