Design patterns are proven solutions to common software design problems. In Java, they help developers write flexible, reusable, and maintainable code by providing standardized approaches to object creation, communication, and behavior.
1. Categories of Design Patterns
Design patterns are generally divided into three main categories:
- Creational – Object creation mechanisms (e.g., Singleton, Factory)
- Structural – Composition of classes/objects (e.g., Adapter, Decorator)
- Behavioral – Object communication and responsibilities (e.g., Strategy, Observer)
2. Common Creational Patterns
Singleton Pattern
Ensures only one instance of a class is created.
java
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
Factory Pattern
Creates objects without exposing instantiation logic.
java
public interface Shape {
void draw();
}
public class Circle implements Shape {
public void draw() { System.out.println("Circle"); }
}
public class ShapeFactory {
public Shape getShape(String type) {
return switch (type) {
case "circle" -> new Circle();
default -> null;
};
}
}
3. Common Structural Patterns
Adapter Pattern
Allows incompatible interfaces to work together.
java
public interface Target {
void request();
}
public class Adaptee {
public void specificRequest() { System.out.println("Specific request"); }
}
public class Adapter implements Target {
private final Adaptee adaptee = new Adaptee();
public void request() { adaptee.specificRequest(); }
}
Decorator Pattern
Adds responsibilities to objects dynamically.
java
public interface Coffee {
String getDescription();
double getCost();
}
public class SimpleCoffee implements Coffee {
public String getDescription() { return "Simple Coffee"; }
public double getCost() { return 5.0; }
}
public class MilkDecorator implements Coffee {
private final Coffee coffee;
public MilkDecorator(Coffee coffee) { this.coffee = coffee; }
public String getDescription() { return coffee.getDescription() + ", Milk"; }
public double getCost() { return coffee.getCost() + 1.0; }
}
4. Common Behavioral Patterns
Strategy Pattern
Encapsulates interchangeable algorithms.
java
public interface PaymentStrategy {
void pay(int amount);
}
public class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) { System.out.println("Paid by credit card: " + amount); }
}
public class ShoppingCart {
private PaymentStrategy strategy;
public void setPaymentStrategy(PaymentStrategy strategy) { this.strategy = strategy; }
public void checkout(int amount) { strategy.pay(amount); }
}
Observer Pattern
Notifies observers of state changes.
java
public interface Observer {
void update(String message);
}
public class Subscriber implements Observer {
public void update(String message) {
System.out.println("Received update: " + message);
}
}
5. Why Use Design Patterns?
- Solve recurring problems with proven solutions
- Improve communication between developers
- Increase code reusability and testability
- Make code easier to maintain and extend
6. Best Practices
- Don’t overuse patterns—use them when they solve a real problem.
- Understand the problem before choosing a pattern.
- Combine patterns when needed (e.g., Factory + Singleton).
- Stick to SOLID principles to guide pattern usage.
Design patterns are essential tools for every serious Java developer. Mastering them equips you to tackle complex design challenges and build robust applications with confidence.