Lesson 16 โข Advanced
OOP Design Patterns
Apply Singleton, Factory, Builder, and Decorator patterns to write professional Java code.
๐ Before You Start
You should be comfortable with:
- OOP & Inheritance (Lessons 9-10) โ classes, polymorphism, extending
- Interfaces (Lesson 11) โ contracts and implementations
- Advanced Methods (Lesson 15) โ method references, lambdas
What You'll Learn
- โ Singleton pattern โ ensure only one instance exists
- โ Factory pattern โ create objects without exposing logic
- โ Builder pattern โ construct complex objects step by step
- โ Decorator pattern โ add behaviour dynamically
- โ Observer pattern โ event-driven communication
- โ When to use each pattern in real projects
1๏ธโฃ Why Design Patterns?
Design patterns are proven solutions to common software design problems. They were popularized by the "Gang of Four" book and remain the lingua franca of professional developers.
๐ก Real-World Analogy: Design patterns are like architectural blueprints. A Singleton is like having one CEO. A Factory is like a car assembly line. A Builder is like ordering a custom pizza. A Decorator is like gift-wrapping โ adding layers without changing the gift.
Three categories: Creational (Singleton, Factory, Builder) manage object creation. Structural (Decorator, Adapter) manage composition. Behavioral (Observer, Strategy) manage communication.
2๏ธโฃ Singleton & Factory Patterns
Singleton: Ensures only one instance of a class exists. Perfect for database connections, configuration managers, and caches.
// Thread-safe Singleton (enum approach)
public enum Database {
INSTANCE;
public void connect() { /* ... */ }
}
// Usage: Database.INSTANCE.connect();Factory: Creates objects without exposing creation logic. The caller asks for a product by type and gets the right subclass back.
public class AnimalFactory {
public static Animal create(String type) {
return switch (type) {
case "dog" -> new Dog();
case "cat" -> new Cat();
default -> throw new IllegalArgumentException("Unknown: " + type);
};
}
}Try It: Singleton & Factory Patterns
Build a database singleton and an animal factory
// ๐ก Try modifying this code and see what happens!
// Singleton & Factory Patterns (Simulated)
console.log("=== Singleton Pattern ===\n");
class Database {
static instance = null;
constructor(name) {
if (Database.instance) return Database.instance;
this.name = name;
this.connections = 0;
Database.instance = this;
}
connect() {
this.connections++;
console.log(" Connected to " + this.name + " (conn #" + this.connections + ")");
...3๏ธโฃ Builder Pattern
The Builder pattern constructs complex objects step by step using method chaining. Each method returns this so calls can be chained fluently.
User user = new User.Builder("Alice")
.email("alice@mail.com")
.age(25)
.role("admin")
.build();When to use: Objects with many optional parameters, SQL query construction, configuration objects, or any case where a constructor with 10+ params would be confusing.
Try It: Builder & Decorator Patterns
Build SQL queries with Builder and wrap coffee orders with Decorator
// ๐ก Try modifying this code and see what happens!
// Builder & Decorator Patterns (Simulated)
console.log("=== Builder Pattern ===\n");
class QueryBuilder {
constructor() { this.parts = { table: "", conditions: [], columns: "*", limit: null, orderBy: null }; }
from(table) { this.parts.table = table; return this; }
select(cols) { this.parts.columns = cols; return this; }
where(cond) { this.parts.conditions.push(cond); return this; }
orderBy(col) { this.parts.orderBy = col;
...4๏ธโฃ Observer Pattern
Analogy: Like a newsletter subscription โ you subscribe once, and whenever there's news, you get notified automatically. No need to keep checking.
// Java: PropertyChangeListener, Observer pattern subject.addObserver(observer); subject.notifyAll(event);
Try It: Observer Pattern & Event System
Build a publish-subscribe event system for notifications
// ๐ก Try modifying this code and see what happens!
// Observer Pattern (Simulated)
console.log("=== Observer Pattern ===\n");
class EventEmitter {
constructor() { this.listeners = {}; }
on(event, callback) {
if (!this.listeners[event]) this.listeners[event] = [];
this.listeners[event].push(callback);
return this; // allow chaining
}
off(event, callback) {
if (this.listeners[event]) {
this.listeners[event] = this.listeners[event].filte
...5๏ธโฃ Common Mistakes
enum singleton or double-checked locking.build() โ invalid objects defeat the purpose.6๏ธโฃ Pro Tips
๐ก Enum Singleton is the safest in Java โ thread-safe, serialization-safe, reflection-proof.
๐ก Builder + immutable objects is a powerful combo. Make all fields final and only settable through the builder.
๐ก In interviews, knowing when NOT to use a pattern is more impressive than knowing the pattern itself.
๐ Quick Reference
| Pattern | Purpose | When to Use |
|---|---|---|
| Singleton | One instance only | Database, config, cache |
| Factory | Create without exposing logic | Object families, plugins |
| Builder | Step-by-step construction | Complex objects, queries |
| Decorator | Add behavior dynamically | Wrapping, middleware |
| Observer | Event notification | UI events, messaging |
๐ Lesson Complete!
You now understand the most important OOP design patterns used in enterprise Java development!
Next: Interfaces, Abstraction & Best Practices โ default methods, sealed interfaces, and interface-first design.
Sign up for free to track which lessons you've completed and get learning reminders.