Design patterns are tried-and-tested solutions to common software design problems. In Java, they help build more maintainable, scalable, and readable code. This article covers three of the most widely used design patterns: Singleton, Factory, and Strategy — all part of the Gang of Four (GoF) patterns.
1. Singleton Pattern
Purpose: Ensures a class has only one instance and provides a global access point to it.
Use Cases:
- Configuration settings
- Logger services
- Database connections
Example:
java
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Best Practice: Use enum Singleton for simplicity and thread safety:
java
public enum AppConfig {
INSTANCE;
}
2. Factory Pattern
Purpose: Creates objects without exposing the instantiation logic to the client.
Use Cases:
- Creating objects based on input or conditions
- Decoupling object creation from implementation
Example:
java
interface Shape {
void draw();
}
class Circle implements Shape {
public void draw() {
System.out.println("Drawing Circle");
}
}
class ShapeFactory {
public static Shape getShape(String type) {
return switch (type) {
case "circle" -> new Circle();
default -> throw new IllegalArgumentException("Unknown shape");
};
}
}
Usage:
java
Shape shape = ShapeFactory.getShape("circle");
shape.draw();
3. Strategy Pattern
Purpose: Defines a family of algorithms and makes them interchangeable at runtime.
Use Cases:
- Dynamic behavior changes (e.g., payment, sorting strategies)
- Avoiding massive
if-else
or switch
statements
Example:
java
interface PaymentStrategy {
void pay(double amount);
}
class CreditCardPayment implements PaymentStrategy {
public void pay(double amount) {
System.out.println("Paid $" + amount + " using credit card.");
}
}
class ShoppingCart {
private PaymentStrategy strategy;
public ShoppingCart(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void checkout(double amount) {
strategy.pay(amount);
}
}
Usage:
java
ShoppingCart cart = new ShoppingCart(new CreditCardPayment());
cart.checkout(100.0);
Benefits of Using Design Patterns
- Improve code readability and maintainability
- Promote reuse and consistency
- Align with SOLID principles (especially Open/Closed & Single Responsibility)
- Make testing and debugging easier
Design patterns are essential tools in every Java developer’s toolkit. Understanding when and how to use them can dramatically improve the quality of your software designs.