1 Design Patterns - Comprehensive Guide

Generated: Tue Feb 3 17:15:34 UTC 2026


CI License: MIT Java Pages GitHub Repo stars

2 Design Patterns in Java β€” Practical, Runnable Examples

A curated, production-oriented collection of classic software design patterns implemented in Java.
Each pattern is expressed as small, focused, runnable code intended to demonstrate intent, structure, and trade-offs β€” not just theory.

This repository is designed as a long-term reference for backend engineers, architects, and senior developers.


2.1 🎯 Objectives


2.2 🧠 Who This Is For


2.3 πŸ›  Tech Stack


2.4 πŸš€ Quick Start

2.4.1 Prerequisites

2.4.2 Build & Test

mvn clean test

2.4.3 Import into IDE

Open the project as a Maven project using pom.xml in IntelliJ IDEA or Eclipse.

2.5 πŸ“š Pattern Index

2.5.1 Creational Patterns

Pattern Folder Typical Use Case
Abstract Factory abstract-factory/ Families of related objects
Builder builder/ Complex object construction
Factory Method factory-method/ Delegating object creation
Prototype prototype/ Cloning costly objects
Singleton singleton/ Controlled global access

2.5.2 Structural Patterns

Pattern Folder Typical Use Case
Adapter adapter/ Interface compatibility
Bridge bridge/ Decoupling abstraction & impl
Composite composite/ Tree structures
Decorator decorator/ Runtime behavior extension
Facade facade/ Simplified subsystem access
Flyweight flyweight/ Memory optimization
Proxy proxy/ Controlled access

2.5.3 Behavioral Patterns

Pattern Folder Typical Use Case
Chain of Responsibility chain/ Request pipelines
Command command/ Action encapsulation
Interpreter interpreter/ DSL-like grammars
Iterator iterator/ Collection traversal
Mediator mediator/ Interaction centralization
Memento memento/ State snapshots
Observer observer/ Event-driven updates
State state/ Workflow/state machines
Strategy strategy/ Algorithm selection
Template Method template-method/ Algorithm skeletons
Visitor visitor/ Operations on object graphs
MVP model-view-presenter/ Presentation separation

2.5.4 Hybrid / Reference Patterns


2.6 🧩 How to Read Each Pattern

For each pattern folder, focus on:

  1. Intent β€” what problem is being solved
  2. Roles β€” participants and responsibilities
  3. Trade-offs β€” costs vs.Β benefits
  4. Alternatives β€” simpler options to consider

Patterns are tools, not goals. Overuse is a design smell.


2.7 πŸ§ͺ Testing Philosophy


2.8 🧭 Design Principles Emphasized


2.9 πŸ›£ Roadmap


2.10 🀝 Contributing

Contributions are welcome and encouraged!

see CONTRIBUTING.md for details.


2.11 πŸ“œ License

2.12 This project is licensed under the MIT License β€” free to use, modify, and distribute.

3 Abstract Factory Pattern

3.1 πŸ“‹ Overview

The Abstract Factory pattern - Provides an interface for creating families of related or dependent objects without specifying their concrete classes.


3.2 🎯 Intent

Problem Solved:

Use When:


3.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
AbstractFactory Interface for creating products
ConcreteFactory Implements product creation
AbstractProduct Product interface
ConcreteProduct Concrete implementations

3.4 πŸ’‘ Code Example

// Abstract Factory
public interface KingdomFactory {
    Castle createCastle();
    King createKing();
    Army createArmy();
}

// Concrete Factories
public class ElfKingdomFactory implements KingdomFactory {
    public Castle createCastle() { return new ElfCastle(); }
    public King createKing() { return new ElfKing(); }
    public Army createArmy() { return new ElfArmy(); }
}

public class DwarfKingdomFactory implements KingdomFactory {
    public Castle createCastle() { return new DwarfCastle(); }
    public King createKing() { return new DwarfKing(); }
    public Army createArmy() { return new DwarfArmy(); }
}

// Usage
KingdomFactory factory = new ElfKingdomFactory();
Castle castle = factory.createCastle();

Reasoning: Client code doesn’t know concrete classes. Entire family changes by swapping factory. Ensures type-safe product combinations.


3.5 πŸ”€ Design Principles


3.6 πŸ“Š Class Diagram

classDiagram
    class Client
    class AbstractFactory {
        <<interface>>
        +createProductA()
        +createProductB()
    }
    class ConcreteFactory1
    class ConcreteFactory2
    class AbstractProductA {
        <<interface>>
    }
    class AbstractProductB {
        <<interface>>
    }
    class ProductA1
    class ProductA2
    class ProductB1
    class ProductB2
    AbstractFactory <|-- ConcreteFactory1
    AbstractFactory <|-- ConcreteFactory2
    AbstractProductA <|-- ProductA1
    AbstractProductA <|-- ProductA2
    AbstractProductB <|-- ProductB1
    AbstractProductB <|-- ProductB2
    ConcreteFactory1 --> ProductA1
    ConcreteFactory1 --> ProductB1
    ConcreteFactory2 --> ProductA2
    ConcreteFactory2 --> ProductB2
    AbstractFactory --> AbstractProductA
    AbstractFactory --> AbstractProductB
    Client --> AbstractFactory
    Client --> AbstractProductA
    Client --> AbstractProductB

3.7 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>AbstractFactory: createProductA()
    AbstractFactory-->>Client: AbstractProductA
    Client->>AbstractFactory: createProductB()
    AbstractFactory-->>Client: AbstractProductB
    Client->>AbstractProductA: use()
    Client->>AbstractProductB: use()

3.8 βš–οΈ Trade-offs

3.8.1 Advantages βœ…

3.8.2 Disadvantages ❌


3.9 🚫 When NOT to Use


3.10 ⚠️ Common Anti-Patterns

Anti-Pattern Issue Solution
Factory returns null use Optional Use appropriate implementation
Leaky abstractions stick to interfaces Use appropriate implementation
Single Responsibility violation separate concerns Use appropriate implementation

3.11 🌍 Real-World Use Cases


3.12 πŸ”— Alternatives & Similar Patterns

Alternative When to Use
Factory Method When…
Builder When…
Prototype When…

3.13 πŸ“ Best Practices

  1. Keep the pattern simple and focused
  2. Document pattern usage in code
  3. Avoid overusing patterns
  4. Test pattern implementations thoroughly
  5. Consider performance implications
  6. Make patterns explicit in architecture
  7. Provide clear examples
  8. Review patterns periodically


3.15 πŸ“š References


4 Adapter Pattern

4.1 πŸ“‹ Overview

This folder contains the Adapter design pattern implementation.


4.2 🎯 Intent

The adapter pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.


4.3 πŸ‘₯ Roles & Responsibilities

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.


4.4 πŸ’‘ Code Example

Please see the src/ directory for complete, executable code examples demonstrating this pattern.


4.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Target {
        <<interface>>
        +request()
    }
    class Adapter {
        +request()
    }
    class Adaptee {
        +specificRequest()
    }
    Client --> Target
    Target <|-- Adapter
    Adapter --> Adaptee

4.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Target: request()
    Target->>Adapter: request()
    Adapter->>Adaptee: specificRequest()
    Adaptee-->>Adapter: result
    Adapter-->>Client: result

4.7 βš–οΈ Trade-offs

4.7.1 Advantages βœ…

4.7.2 Disadvantages ❌


4.8 🚫 When NOT to Use


4.9 ⚠️ Common Anti-Patterns

Anti-Pattern Issue Solution
Overuse Using pattern unnecessarily Apply YAGNI principle
Misapplication Wrong context for pattern Study pattern requirements
Complexity Pattern makes code harder Simplify or choose different pattern

4.10 🌍 Real-World Use Cases

This pattern appears frequently in: - Enterprise applications - Framework and library design - System integration scenarios


4.11 πŸ”— Alternatives & Similar Patterns


4.12 πŸ“ Best Practices

  1. Understand the problem before applying the pattern
  2. Document your pattern usage clearly
  3. Keep implementations simple
  4. Test thoroughly
  5. Consider performance implications
  6. Review periodically for improvements
  7. Teach team members about the pattern
  8. Refactor if pattern no longer applies

4.13 πŸ“š References

For detailed implementation, see the source files in src/.


5 Bridge Pattern

5.1 πŸ“‹ Overview

This folder contains the Bridge design pattern implementation.


5.2 🎯 Intent

The bridge pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.


5.3 πŸ‘₯ Roles & Responsibilities

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.


5.4 πŸ’‘ Code Example

Please see the src/ directory for complete, executable code examples demonstrating this pattern.


5.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Abstraction {
        -implementor: Implementor
        +operation()
    }
    class RefinedAbstraction
    class Implementor {
        <<interface>>
        +operationImpl()
    }
    class ConcreteImplementorA
    class ConcreteImplementorB
    Client --> Abstraction
    Abstraction <|-- RefinedAbstraction
    Implementor <|-- ConcreteImplementorA
    Implementor <|-- ConcreteImplementorB
    Abstraction --> Implementor

5.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Abstraction: operation()
    Abstraction->>Implementor: operationImpl()
    Implementor-->>Abstraction: result
    Abstraction-->>Client: result

5.7 βš–οΈ Trade-offs

5.7.1 Advantages βœ…

5.7.2 Disadvantages ❌


5.8 🚫 When NOT to Use


5.9 ⚠️ Common Anti-Patterns

Anti-Pattern Issue Solution
Overuse Using pattern unnecessarily Apply YAGNI principle
Misapplication Wrong context for pattern Study pattern requirements
Complexity Pattern makes code harder Simplify or choose different pattern

5.10 🌍 Real-World Use Cases

This pattern appears frequently in: - Enterprise applications - Framework and library design - System integration scenarios


5.11 πŸ”— Alternatives & Similar Patterns


5.12 πŸ“ Best Practices

  1. Understand the problem before applying the pattern
  2. Document your pattern usage clearly
  3. Keep implementations simple
  4. Test thoroughly
  5. Consider performance implications
  6. Review periodically for improvements
  7. Teach team members about the pattern
  8. Refactor if pattern no longer applies

5.13 πŸ“š References

For detailed implementation, see the source files in src/.


6 Builder Pattern

6.1 πŸ“‹ Overview

The Builder Pattern is a creational pattern that constructs complex objects step-by-step, separating the construction logic from the representation. It provides a fluent, readable interface for building objects with many optional parameters or complex initialization logic.


6.2 🎯 Intent

Problem Solved: - Creating objects with many parameters is error-prone and produces unreadable code - Objects have optional and mandatory parameters; telescoping constructors become unwieldy - Complex initialization logic should be separated from object representation - You need to construct immutable objects while maintaining readability

Use When: - Objects have 3+ optional parameters - You need to build immutable objects with validation - Construction logic is complex or multi-step - You want to improve code readability over constructor overloading


6.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Product The complex object being constructed (e.g., Hero)
Builder Abstract interface defining construction steps
Concrete Builder Implements construction steps, accumulates result
Director (Optional) Orchestrates the builder to construct products in a specific order
Client Uses builder to construct products

Key Characteristics: - Fluent interface enabling method chaining - Separation of construction from representation - Step-by-step object assembly - Validation at build stage


6.4 πŸ’‘ Implementation Example

// Product: Complex object to build
public class Hero {
    private final String name;
    private final Profession profession;
    private final HairType hairType;
    private final HairColor hairColor;
    private final Armor armor;
    private final Weapon weapon;

    private Hero(HeroBuilder builder) {
        this.name = builder.name;
        this.profession = builder.profession;
        this.hairType = builder.hairType;
        this.hairColor = builder.hairColor;
        this.armor = builder.armor;
        this.weapon = builder.weapon;
    }

    // Builder: Inner class managing construction
    public static class HeroBuilder {
        private final String name;
        private final Profession profession;
        private HairType hairType;
        private HairColor hairColor;
        private Armor armor;
        private Weapon weapon;

        // Mandatory parameters in constructor
        public HeroBuilder(Profession profession, String name) {
            this.profession = profession;
            this.name = name;
        }

        // Fluent methods for optional parameters
        public HeroBuilder withHairType(HairType hairType) {
            this.hairType = hairType;
            return this;
        }

        public HeroBuilder withHairColor(HairColor hairColor) {
            this.hairColor = hairColor;
            return this;
        }

        public HeroBuilder withArmor(Armor armor) {
            this.armor = armor;
            return this;
        }

        public HeroBuilder withWeapon(Weapon weapon) {
            this.weapon = weapon;
            return this;
        }

        // Build: Final step returning the constructed product
        public Hero build() {
            return new Hero(this);
        }
    }
}

// Usage: Clean, readable, chainable construction
Hero mage = new Hero.HeroBuilder(Profession.MAGE, "Merlin")
    .withHairColor(HairColor.BLACK)
    .withWeapon(Weapon.STAFF)
    .build();

Reasoning: - Separates object construction from its representation - Fluent interface improves readability dramatically - Mandatory parameters enforced in constructor - Optional parameters via fluent methods - Immutability achieved through private constructor


6.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Director {
        -builder: Builder
        +construct()
    }
    class Builder {
        <<interface>>
        +buildPartA()
        +buildPartB()
        +getResult()
    }
    class ConcreteBuilder
    class Product
    Client --> Director
    Director --> Builder
    Builder <|-- ConcreteBuilder
    ConcreteBuilder --> Product

6.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Director: construct()
    Director->>Builder: buildPartA()
    Director->>Builder: buildPartB()
    Builder-->>Director: done
    Client->>Builder: getResult()
    Builder-->>Client: Product

6.7 πŸ”€ Design Principles Emphasized

Principle How Applied
Single Responsibility Builder manages construction; Product manages data
Separation of Concerns Object representation separated from construction logic
Composition over Inheritance Builder uses composition to accumulate object state
Fluent Interface Method chaining improves readability
Immutability Constructor is private; object state set via builder

6.8 βš–οΈ Trade-offs

6.8.1 Advantages βœ…

6.8.2 Disadvantages ❌


6.9 🚫 When NOT to Use

Scenario Why Avoid
Simple Objects Objects with 1-2 parameters; use direct constructors
Mutable Objects Builder is designed for immutability; doesn’t benefit mutable objects
Performance Critical Memory overhead of builder may matter in high-frequency scenarios
All Parameters Optional If no mandatory parameters, builder doesn’t enforce constraints
Frequent Modification If object needs modification after creation, use setters instead

6.10 ⚠️ Common Anti-Patterns & Misuses

Anti-Pattern Problem Solution
Shared Builder Across Threads Race conditions when building concurrent products Create new builder per thread; builders not thread-safe
Builder Without Validation Invalid objects created if validation deferred Implement validation in build() method
All-Optional Builder No constraints on required parameters Enforce mandatory params in builder constructor
Complex Directors Director hides builder complexity instead of simplifying it Director should orchestrate, not complicate
Mutable Product After Build Product state modified after construction defeats builder purpose Keep product immutable; add new builder if changes needed
Builder with Setters Contradicts immutability goal Use only fluent builder methods, no setters on product

6.11 🌍 Real-World Use Cases

6.11.1 Java StringBuilder

// StringBuilder is a builder for immutable String
String text = new StringBuilder()
    .append("Hello")
    .append(" ")
    .append("World")
    .toString();

6.11.2 Google Guava - ImmutableList

// Guava uses builder for complex immutable collections
ImmutableList<String> list = ImmutableList.builder()
    .add("item1")
    .add("item2")
    .build();

6.11.3 Lombok @Builder

// Lombok annotation auto-generates builder
@Builder
public class User {
    private String name;
    private String email;
    private int age;
}

// Usage
User user = User.builder()
    .name("Alice")
    .email("alice@example.com")
    .age(30)
    .build();

6.11.4 HTTP Clients (OkHttp)

// OkHttp Request builder
Request request = new Request.Builder()
    .url("https://example.com")
    .addHeader("User-Agent", "MyApp")
    .post(body)
    .build();

6.11.5 Apache Commons - Configuration

// Configuration builder with fluent interface
Configuration config = new Configuration.Builder()
    .setDatabaseUrl("jdbc:mysql://localhost")
    .setMaxConnections(50)
    .setReadTimeout(5000)
    .build();

6.12 πŸ”— Alternatives & Similar Patterns

Alternative When to Prefer
Telescoping Constructor For simple objects with few parameters
JavaBeans with Setters When mutability is acceptable; not ideal for immutability
Factory Method For creating simple objects or choosing implementations
Abstract Factory When building families of related objects
Fluent Configuration Lightweight alternative to builder for configuration objects

6.13 πŸ“ Best Practices

  1. Enforce Mandatory Parameters: Place required params in builder constructor
  2. Use Method Chaining: Return this for fluent interface
  3. Validate in Build: Check constraints before creating product
  4. Keep Builder Simple: Avoid complex logic; delegate to product
  5. Consider Lombok: Use @Builder annotation to auto-generate builder code
  6. Make Product Immutable: Private constructor, final fields
  7. Document Optional Parameters: Clarify defaults and constraints
  8. Provide Copy Constructor: Allow building new instance from existing product


6.15 πŸ“š References


7 Chain of Responsibility Pattern

7.1 πŸ“‹ Overview

The Chain of Responsibility pattern passes a request along a chain of handlers. Each handler decides either to process the request or pass it to the next handler in the chain.


7.2 🎯 Intent

Problem Solved: - You need to process a request by multiple handlers without knowing which handler will process it in advance - You want to decouple the sender of a request from its receiver - You want to allow adding/removing handlers dynamically

Use When: - Multiple objects may handle a request - You don’t know in advance which object should handle the request - You want to issue a request to multiple handlers without specifying the receiver explicitly


7.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Handler Defines interface for handling requests and linking handlers
ConcreteHandler Handles requests or passes them to next handler
Client Initiates request into the chain

7.4 πŸ’‘ Code Example

public abstract class RequestHandler {
    protected RequestHandler nextHandler;
    
    public void setNextHandler(RequestHandler nextHandler) {
        this.nextHandler = nextHandler;
    }
    
    public abstract void handleRequest(Request request);
}

public class ConcreteHandler extends RequestHandler {
    @Override
    public void handleRequest(Request request) {
        if (canHandle(request)) {
            process(request);
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        }
    }
    
    private boolean canHandle(Request request) {
        return request.getType() == RequestType.TYPE_A;
    }
    
    private void process(Request request) {
        System.out.println("Processing request: " + request);
    }
}

// Usage
RequestHandler handler1 = new ConcreteHandler();
RequestHandler handler2 = new ConcreteHandler();
handler1.setNextHandler(handler2);
handler1.handleRequest(new Request(RequestType.TYPE_A));

Reasoning: Decouples sender from receiver; handlers decide whether to handle or pass on request dynamically.


7.5 πŸ”€ Design Principles


7.6 πŸ“Š Class Diagram

classDiagram
    class Client
    class Request
    class Handler {
        <<abstract>>
        -next: Handler
        +setNext(h: Handler)
        +handle(r: Request)
    }
    class ConcreteHandlerA
    class ConcreteHandlerB
    Client --> Handler
    Handler <|-- ConcreteHandlerA
    Handler <|-- ConcreteHandlerB
    Handler --> Handler

7.7 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>HandlerA: handle(request)
    alt canHandle
        HandlerA-->>Client: handled
    else pass
        HandlerA->>HandlerB: handle(request)
        HandlerB-->>Client: handled
    end

7.8 βš–οΈ Trade-offs

7.8.1 Advantages βœ…

7.8.2 Disadvantages ❌


7.9 🚫 When NOT to Use


7.10 ⚠️ Common Anti-Patterns

Anti-Pattern Problem Solution
Infinite Loops Circular chain references Prevent circular chains
Silent Failures Request disappears without handling Always handle or log
God Handler Handler does too much Split into multiple handlers

7.11 🌍 Real-World Use Cases


7.12 πŸ“ Best Practices

  1. Define clear handler contract
  2. Document chain behavior
  3. Handle unprocessed requests
  4. Avoid infinite loops in chain
  5. Keep handlers focused
  6. Consider handler ordering
  7. Log at each stage
  8. Provide default handler

7.13 πŸ“š References


8 Command Pattern

8.1 πŸ“‹ Overview

The Command pattern encapsulates a request as an object, allowing parameterization of clients with different requests, queuing of requests, and logging of requests.


8.2 🎯 Intent

Problem Solved: - Encapsulate a request as an object - Decouple the object that invokes an operation from the one that performs it - Allow undo/redo functionality - Queue commands for deferred execution


8.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Command Declares interface for executing operation
ConcreteCommand Binds receiver to action
Receiver Knows how to perform actual work
Invoker Asks command to carry out request
Client Creates ConcreteCommand

8.4 πŸ’‘ Code Example

public interface Command {
    void execute();
    void undo();
}

public class LightOnCommand implements Command {
    private Light light;
    
    public LightOnCommand(Light light) {
        this.light = light;
    }
    
    @Override
    public void execute() {
        light.on();
    }
    
    @Override
    public void undo() {
        light.off();
    }
}

// Invoker
public class RemoteControl {
    private List<Command> commands = new ArrayList<>();
    
    public void pressButton(Command command) {
        command.execute();
        commands.add(command);
    }
    
    public void undo() {
        if (!commands.isEmpty()) {
            commands.remove(commands.size() - 1).undo();
        }
    }
}

// Usage
RemoteControl remote = new RemoteControl();
remote.pressButton(new LightOnCommand(light));
remote.undo();

Reasoning: Requests encapsulated as objects enabling queuing, undoing, and macro commands.


8.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Invoker {
        -command: Command
        +setCommand(c: Command)
        +invoke()
    }
    class Command {
        <<interface>>
        +execute()
    }
    class ConcreteCommand
    class Receiver {
        +action()
    }
    Client --> Invoker
    Invoker --> Command
    Command <|-- ConcreteCommand
    ConcreteCommand --> Receiver

8.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Invoker: setCommand(cmd)
    Client->>Invoker: invoke()
    Invoker->>Command: execute()
    Command->>Receiver: action()

8.7 βš–οΈ Trade-offs

8.7.1 Advantages βœ…

8.7.2 Disadvantages ❌


8.8 🌍 Real-World Use Cases


8.9 πŸ“š References


9 Composite Pattern

9.1 πŸ“‹ Overview

This folder contains the Composite design pattern implementation.


9.2 🎯 Intent

The composite pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.


9.3 πŸ‘₯ Roles & Responsibilities

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.


9.4 πŸ’‘ Code Example

Please see the src/ directory for complete, executable code examples demonstrating this pattern.


9.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Component {
        <<interface>>
        +operation()
    }
    class Leaf
    class Composite {
        -children: List<Component>
        +add(c: Component)
        +operation()
    }
    Client --> Component
    Component <|-- Leaf
    Component <|-- Composite
    Composite --> Component

9.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Composite: operation()
    loop children
        Composite->>Component: operation()
    end
    Composite-->>Client: result

9.7 βš–οΈ Trade-offs

9.7.1 Advantages βœ…

9.7.2 Disadvantages ❌


9.8 🚫 When NOT to Use


9.9 ⚠️ Common Anti-Patterns

Anti-Pattern Issue Solution
Overuse Using pattern unnecessarily Apply YAGNI principle
Misapplication Wrong context for pattern Study pattern requirements
Complexity Pattern makes code harder Simplify or choose different pattern

9.10 🌍 Real-World Use Cases

This pattern appears frequently in: - Enterprise applications - Framework and library design - System integration scenarios


9.11 πŸ”— Alternatives & Similar Patterns


9.12 πŸ“ Best Practices

  1. Understand the problem before applying the pattern
  2. Document your pattern usage clearly
  3. Keep implementations simple
  4. Test thoroughly
  5. Consider performance implications
  6. Review periodically for improvements
  7. Teach team members about the pattern
  8. Refactor if pattern no longer applies

9.13 πŸ“š References

For detailed implementation, see the source files in src/.


10 Decorator Pattern

10.1 πŸ“‹ Overview

This folder contains the Decorator design pattern implementation.


10.2 🎯 Intent

The decorator pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.


10.3 πŸ‘₯ Roles & Responsibilities

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.


10.4 πŸ’‘ Code Example

Please see the src/ directory for complete, executable code examples demonstrating this pattern.


10.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Component {
        <<interface>>
        +operation()
    }
    class ConcreteComponent
    class Decorator {
        -component: Component
        +operation()
    }
    class ConcreteDecorator
    Client --> Component
    Component <|-- ConcreteComponent
    Component <|-- Decorator
    Decorator <|-- ConcreteDecorator
    Decorator --> Component

10.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Decorator: operation()
    Decorator->>Component: operation()
    Component-->>Decorator: result
    Decorator-->>Client: result

10.7 βš–οΈ Trade-offs

10.7.1 Advantages βœ…

10.7.2 Disadvantages ❌


10.8 🚫 When NOT to Use


10.9 ⚠️ Common Anti-Patterns

Anti-Pattern Issue Solution
Overuse Using pattern unnecessarily Apply YAGNI principle
Misapplication Wrong context for pattern Study pattern requirements
Complexity Pattern makes code harder Simplify or choose different pattern

10.10 🌍 Real-World Use Cases

This pattern appears frequently in: - Enterprise applications - Framework and library design - System integration scenarios


10.11 πŸ”— Alternatives & Similar Patterns


10.12 πŸ“ Best Practices

  1. Understand the problem before applying the pattern
  2. Document your pattern usage clearly
  3. Keep implementations simple
  4. Test thoroughly
  5. Consider performance implications
  6. Review periodically for improvements
  7. Teach team members about the pattern
  8. Refactor if pattern no longer applies

10.13 πŸ“š References

For detailed implementation, see the source files in src/.


11 Double-Checked Locking Pattern

11.1 πŸ“‹ Overview

The Double-Checked Locking pattern is a thread-safe lazy initialization technique that minimizes synchronization overhead.


11.2 🎯 Intent

Problem Solved: - Thread-safe lazy initialization - Minimize synchronization overhead - Defer object creation until needed - Efficient repeated access


11.3 πŸ’‘ Implementation

public class DoubleCheckedLocking {
    private volatile static Instance instance;
    
    public static Instance getInstance() {
        if (instance == null) {
            synchronized(DoubleCheckedLocking.class) {
                if (instance == null) {
                    instance = new Instance();
                }
            }
        }
        return instance;
    }
}

11.4 ⚠️ Considerations


11.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Singleton {
        -static instance: Singleton
        +getInstance(): Singleton
    }
    Client --> Singleton

11.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Singleton: getInstance()
    alt instance == null
        Client->>Singleton: synchronize
        Singleton->>Singleton: create instance
    end
    Singleton-->>Client: instance

11.7 πŸ“š References


12 Facade Pattern

12.1 πŸ“‹ Overview

This folder contains the Facade design pattern implementation.


12.2 🎯 Intent

The facade pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.


12.3 πŸ‘₯ Roles & Responsibilities

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.


12.4 πŸ’‘ Code Example

Please see the src/ directory for complete, executable code examples demonstrating this pattern.


12.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Facade {
        +operation()
    }
    class SubsystemA
    class SubsystemB
    class SubsystemC
    Client --> Facade
    Facade --> SubsystemA
    Facade --> SubsystemB
    Facade --> SubsystemC

12.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Facade: operation()
    Facade->>SubsystemA: doA()
    Facade->>SubsystemB: doB()
    Facade->>SubsystemC: doC()
    Facade-->>Client: result

12.7 βš–οΈ Trade-offs

12.7.1 Advantages βœ…

12.7.2 Disadvantages ❌


12.8 🚫 When NOT to Use


12.9 ⚠️ Common Anti-Patterns

Anti-Pattern Issue Solution
Overuse Using pattern unnecessarily Apply YAGNI principle
Misapplication Wrong context for pattern Study pattern requirements
Complexity Pattern makes code harder Simplify or choose different pattern

12.10 🌍 Real-World Use Cases

This pattern appears frequently in: - Enterprise applications - Framework and library design - System integration scenarios


12.11 πŸ”— Alternatives & Similar Patterns


12.12 πŸ“ Best Practices

  1. Understand the problem before applying the pattern
  2. Document your pattern usage clearly
  3. Keep implementations simple
  4. Test thoroughly
  5. Consider performance implications
  6. Review periodically for improvements
  7. Teach team members about the pattern
  8. Refactor if pattern no longer applies

12.13 πŸ“š References

For detailed implementation, see the source files in src/.


13 Factory Method Pattern

13.1 πŸ“‹ Overview

The Factory Method Pattern defines an interface for creating an object, letting subclasses decide which class to instantiate.


13.2 🎯 Intent

Problem Solved: - You need to create objects but don’t know the concrete class until runtime - You want subclasses to specify the objects they create - Object creation logic should be separate from usage

Use When: - A class cannot anticipate the type of objects it needs to create - You want subclasses to specify the objects they create - Object creation logic should be separate from business logic


13.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Creator Declares factory method; may provide default implementation
ConcreteCreator Overrides factory method to create specific product
Product Declares interface for objects
ConcreteProduct Implements product interface

13.4 πŸ’‘ Code Example

// Product Interface
public interface Transport {
    void deliver(String cargo);
}

// Concrete Products
public class Truck implements Transport {
    @Override
    public void deliver(String cargo) {
        System.out.println("Truck delivering: " + cargo);
    }
}

// Creator (Abstract)
public abstract class Logistics {
    abstract Transport createTransport();
    
    public void planDelivery(String cargo) {
        Transport transport = createTransport();
        transport.deliver(cargo);
    }
}

// Concrete Creator
public class RoadLogistics extends Logistics {
    @Override
    Transport createTransport() {
        return new Truck();
    }
}

// Usage
Logistics logistics = new RoadLogistics();
logistics.planDelivery("Package");

Reasoning: Clients depend on abstractions, not concrete classes. Subclasses decide what product to create. Promotes loose coupling and flexibility.


13.5 πŸ”€ Design Principles


13.6 πŸ“Š Class Diagram

classDiagram
    class Client
    class Creator {
        <<abstract>>
        +factoryMethod(): Product
        +anOperation()
    }
    class ConcreteCreator
    class Product {
        <<interface>>
        +use()
    }
    class ConcreteProduct
    Client --> Creator
    Creator <|-- ConcreteCreator
    Product <|-- ConcreteProduct
    Creator --> Product

13.7 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Creator: anOperation()
    Creator->>Creator: factoryMethod()
    Creator->>Product: use()
    Product-->>Creator: result
    Creator-->>Client: result

13.8 βš–οΈ Trade-offs

13.8.1 Advantages βœ…

13.8.2 Disadvantages ❌


13.9 🚫 When NOT to Use


13.10 ⚠️ Common Anti-Patterns

Anti-Pattern Problem Solution
Over-Abstracting Creating factory for every object Use only when creation logic is complex
Leaky Abstractions Creator exposes product implementation Keep abstractions strict
Mixing Responsibilities Creator also validates/processes Separate concerns

13.11 🌍 Real-World Use Cases


13.12 πŸ”— Alternatives & Similar Patterns

Alternative When to Use
Abstract Factory When managing families of related products
Builder When object construction is complex
Prototype When cloning is more efficient

13.13 πŸ“ Best Practices

  1. Keep factory interface simple and intuitive
  2. Avoid making factory methods do too much
  3. Document expected exceptions
  4. Provide clear naming for factory methods
  5. Consider static factory methods for simplicity
  6. Ensure thread-safety if needed
  7. Validate inputs before creating objects
  8. Provide sensible defaults where possible


13.15 πŸ“š References


14 Filter Pattern

14.1 πŸ“‹ Overview

The Filter pattern (or Criteria pattern) provides a way to filter collections of objects using different criteria in a flexible and reusable manner.


14.2 🎯 Intent

Problem Solved: - Filter collections by different criteria - Combine multiple filter criteria - Avoid multiple if-else statements - Enable reusable filter components


14.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Criteria Defines filtering interface
ConcreteCriteria Implements specific filter logic
Filter Applies criteria to collection

14.4 πŸ’‘ Implementation


14.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Criteria {
        <<interface>>
        +meetCriteria(items)
    }
    class ConcreteCriteriaA
    class ConcreteCriteriaB
    class AndCriteria
    class OrCriteria
    Client --> Criteria
    Criteria <|-- ConcreteCriteriaA
    Criteria <|-- ConcreteCriteriaB
    Criteria <|-- AndCriteria
    Criteria <|-- OrCriteria
    AndCriteria --> Criteria
    OrCriteria --> Criteria

14.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Criteria: meetCriteria(items)
    Criteria-->>Client: filteredItems

14.7 βš–οΈ Trade-offs

14.7.1 Advantages βœ…

14.7.2 Disadvantages ❌


14.8 🌍 Real-World Use Cases


14.9 πŸ“š References


15 Flyweight Pattern

15.1 πŸ“‹ Overview

This folder contains the Flyweight design pattern implementation.


15.2 🎯 Intent

The flyweight pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.


15.3 πŸ‘₯ Roles & Responsibilities

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.


15.4 πŸ’‘ Code Example

Please see the src/ directory for complete, executable code examples demonstrating this pattern.


15.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Flyweight {
        <<interface>>
        +operation(extrinsic)
    }
    class ConcreteFlyweight
    class FlyweightFactory {
        -pool: Map
        +getFlyweight(key)
    }
    Client --> FlyweightFactory
    Flyweight <|-- ConcreteFlyweight
    FlyweightFactory --> Flyweight

15.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>FlyweightFactory: getFlyweight(key)
    FlyweightFactory-->>Client: Flyweight
    Client->>Flyweight: operation(extrinsicState)

15.7 βš–οΈ Trade-offs

15.7.1 Advantages βœ…

15.7.2 Disadvantages ❌


15.8 🚫 When NOT to Use


15.9 ⚠️ Common Anti-Patterns

Anti-Pattern Issue Solution
Overuse Using pattern unnecessarily Apply YAGNI principle
Misapplication Wrong context for pattern Study pattern requirements
Complexity Pattern makes code harder Simplify or choose different pattern

15.10 🌍 Real-World Use Cases

This pattern appears frequently in: - Enterprise applications - Framework and library design - System integration scenarios


15.11 πŸ”— Alternatives & Similar Patterns


15.12 πŸ“ Best Practices

  1. Understand the problem before applying the pattern
  2. Document your pattern usage clearly
  3. Keep implementations simple
  4. Test thoroughly
  5. Consider performance implications
  6. Review periodically for improvements
  7. Teach team members about the pattern
  8. Refactor if pattern no longer applies

15.13 πŸ“š References

For detailed implementation, see the source files in src/.


16 Interpreter Pattern

16.1 πŸ“‹ Overview

The Interpreter pattern defines a grammatical representation for a language and an interpreter to interpret sentences in that language.


16.2 🎯 Intent

Problem Solved: - Define grammar for domain-specific language - Parse and execute expressions - Build abstract syntax trees - Evaluate language sentences


16.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
AbstractExpression Defines interpret interface
TerminalExpression Implements primitive expressions
NonTerminalExpression Implements composite expressions
Context Global information for interpreter

16.4 πŸ’‘ Implementation


16.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Context
    class AbstractExpression {
        <<interface>>
        +interpret(ctx: Context)
    }
    class TerminalExpression
    class NonterminalExpression {
        -left: AbstractExpression
        -right: AbstractExpression
    }
    Client --> AbstractExpression
    AbstractExpression <|-- TerminalExpression
    AbstractExpression <|-- NonterminalExpression
    AbstractExpression --> Context
    NonterminalExpression --> AbstractExpression

16.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>AbstractExpression: interpret(context)
    AbstractExpression->>AbstractExpression: interpret(child)
    AbstractExpression-->>Client: result

16.7 βš–οΈ Trade-offs

16.7.1 Advantages βœ…

16.7.2 Disadvantages ❌


16.8 🌍 Real-World Use Cases


16.9 πŸ“š References


17 Iterator Pattern

17.1 πŸ“‹ Overview

The Iterator pattern provides a way to access elements of a collection sequentially without exposing its underlying representation.


17.2 🎯 Intent

Problem Solved: - Access collection elements without exposing structure - Support multiple simultaneous traversals - Provide uniform interface for different collections - Hide collection implementation details


17.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Iterator Defines interface for traversal
ConcreteIterator Implements traversal logic
Collection Defines interface for creating iterator
ConcreteCollection Returns ConcreteIterator

17.4 πŸ’‘ Implementation

Java’s Iterator interface: - hasNext(): Check if more elements - next(): Get next element - remove(): Remove current element


17.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Iterator {
        <<interface>>
        +hasNext()
        +next()
    }
    class ConcreteIterator
    class Aggregate {
        <<interface>>
        +createIterator(): Iterator
    }
    class ConcreteAggregate
    Client --> Aggregate
    Aggregate <|-- ConcreteAggregate
    Iterator <|-- ConcreteIterator
    ConcreteAggregate --> ConcreteIterator

17.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Aggregate: createIterator()
    Aggregate-->>Client: Iterator
    loop until done
        Client->>Iterator: hasNext()
        Client->>Iterator: next()
    end

17.7 βš–οΈ Trade-offs

17.7.1 Advantages βœ…

17.7.2 Disadvantages ❌


17.8 🌍 Real-World Use Cases


17.9 πŸ“š References


18 Lazy Sequence Pattern

18.1 πŸ“‹ Overview

The Lazy Sequence pattern defers sequence element computation until they’re actually accessed, enabling efficient processing of potentially infinite sequences.


18.2 🎯 Intent

Problem Solved: - Defer expensive computations - Handle potentially infinite sequences - Support streaming data processing - Reduce memory usage


18.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
LazySequence Defers element computation
ElementGenerator Generates individual elements
Client Accesses elements on demand

18.4 πŸ’‘ Implementation


18.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class LazySequence {
        -cache: Map
        -generator: ElementGenerator
        +get(index)
    }
    class ElementGenerator {
        <<interface>>
        +compute(index)
    }
    Client --> LazySequence
    LazySequence --> ElementGenerator

18.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>LazySequence: get(index)
    alt cached
        LazySequence-->>Client: element
    else not cached
        LazySequence->>ElementGenerator: compute(index)
        ElementGenerator-->>LazySequence: element
        LazySequence-->>Client: element
    end

18.7 βš–οΈ Trade-offs

18.7.1 Advantages βœ…

18.7.2 Disadvantages ❌


18.8 🌍 Real-World Use Cases


18.9 πŸ“š References


19 Mediator Pattern

19.1 πŸ“‹ Overview

The Mediator pattern defines an object that encapsulates how a set of objects interact. It promotes loose coupling by keeping objects from referring to each other explicitly, and lets you vary their interaction independently.


19.2 🎯 Intent

Problem Solved: - Objects communicate in complex ways - Direct references create tight coupling - Communication logic scattered across classes - Adding new interaction types requires modifications


19.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Mediator Defines interface for communication
ConcreteMediator Implements interaction logic
Colleague Communicates only with mediator
- ConcreteColleague Implements colleague behavior

19.4 πŸ’‘ Implementation


19.5 πŸ“Š Class Diagram

classDiagram
    class Mediator {
        <<interface>>
        +notify(sender, event)
    }
    class ConcreteMediator
    class Colleague {
        -mediator: Mediator
        +send(event)
    }
    class ColleagueA
    class ColleagueB
    Mediator <|-- ConcreteMediator
    Colleague <|-- ColleagueA
    Colleague <|-- ColleagueB
    Colleague --> Mediator
    ConcreteMediator --> ColleagueA
    ConcreteMediator --> ColleagueB

19.6 πŸ”„ Sequence Diagram

sequenceDiagram
    participant ColleagueA
    participant Mediator
    participant ColleagueB
    ColleagueA->>Mediator: notify(A, event)
    Mediator->>ColleagueB: receive(event)

19.7 βš–οΈ Trade-offs

19.7.1 Advantages βœ…

19.7.2 Disadvantages ❌


19.8 🌍 Real-World Use Cases


19.9 πŸ“š References


20 Memento Pattern

20.1 πŸ“‹ Overview

The Memento pattern captures and externalizes an object’s internal state without violating encapsulation, and allows the object to be restored to this state later.


20.2 🎯 Intent

Problem Solved: - Save and restore object state - Implement undo/redo functionality - Without exposing internal structure - Without violating encapsulation


20.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Originator Creates memento, uses memento to restore state
Memento Stores state snapshot
Caretaker Manages mementos

20.4 πŸ’‘ Implementation


20.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Originator {
        +createMemento(): Memento
        +restore(m: Memento)
    }
    class Memento
    class Caretaker {
        -history: List<Memento>
    }
    Client --> Originator
    Client --> Caretaker
    Originator --> Memento
    Caretaker --> Memento

20.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Originator: createMemento()
    Originator-->>Client: Memento
    Client->>Caretaker: store(memento)
    Client->>Originator: restore(memento)

20.7 βš–οΈ Trade-offs

20.7.1 Advantages βœ…

20.7.2 Disadvantages ❌


20.8 🌍 Real-World Use Cases


20.9 πŸ“š References


21 Method Object Pattern

21.1 πŸ“‹ Overview

The Method Object pattern converts a method into an object, enabling flexible method parameter passing and invocation.


21.2 🎯 Intent

Problem Solved: - Complex methods with many parameters - Need to pass methods as parameters - Deferred method execution - Method state management


21.3 πŸ‘₯ Roles & Responsibility


21.4 πŸ“Š Class Diagram

classDiagram
    class Client
    class MethodObject {
        <<interface>>
        +execute()
    }
    class ConcreteMethodObject
    class Host {
        +helper()
    }
    Client --> MethodObject
    MethodObject <|-- ConcreteMethodObject
    ConcreteMethodObject --> Host

21.5 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>MethodObject: execute()
    MethodObject->>Host: helper()

21.6 🌍 Real-World Use Cases


21.7 πŸ“š References


22 Model-View-Presenter Pattern

22.1 πŸ“‹ Overview

The Model-View-Presenter (MVP) pattern separates presentation logic from business logic by introducing a presenter component that mediates between the view and model.


22.2 🎯 Intent

Problem Solved: - Separate UI from business logic - Make UI components testable - Enable code reuse across UI frameworks - Improve maintainability of UI code


22.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Model Business logic and data
View Displays data, handles user interaction
Presenter Coordinates Model and View

22.4 πŸ’‘ Implementation


22.5 πŸ“Š Class Diagram

classDiagram
    class Model
    class View {
        <<interface>>
        +render(data)
    }
    class Presenter {
        -model: Model
        -view: View
        +onViewEvent()
    }
    class ConcreteView
    View <|-- ConcreteView
    Presenter --> Model
    Presenter --> View
    ConcreteView --> Presenter

22.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor User
    participant View
    participant Presenter
    participant Model
    User->>View: interact()
    View->>Presenter: event()
    Presenter->>Model: update()
    Model-->>Presenter: data
    Presenter->>View: render(data)

22.7 βš–οΈ Trade-offs

22.7.1 Advantages βœ…

22.7.2 Disadvantages ❌


22.8 🌍 Real-World Use Cases


22.9 πŸ“š References


23 Null Object Pattern

23.1 πŸ“‹ Overview

The Null Object pattern provides an object as a surrogate for null references, avoiding null checks throughout the code.


23.2 🎯 Intent

Problem Solved: - Eliminate null reference checks - Provide default behavior for null case - Improve code clarity - Reduce NullPointerException risks


23.3 πŸ’‘ Implementation

Instead of:

if (logger != null) {
    logger.log("message");
}

Use:

logger.log("message");  // Works with NullLogger

23.4 πŸ“Š Class Diagram

classDiagram
    class Client
    class AbstractObject {
        <<interface>>
        +operation()
    }
    class RealObject
    class NullObject
    Client --> AbstractObject
    AbstractObject <|-- RealObject
    AbstractObject <|-- NullObject

23.5 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>AbstractObject: operation()
    AbstractObject-->>Client: result

23.6 βš–οΈ Trade-offs

23.6.1 Advantages βœ…

23.6.2 Disadvantages ❌


23.7 🌍 Real-World Use Cases


23.8 πŸ“š References


24 Observer Pattern

24.1 πŸ“‹ Overview

The Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified automatically.


24.2 🎯 Intent

Problem Solved: - An object’s state changes and other objects need to be notified - Notify multiple objects without tight coupling - Enable event-driven architecture


24.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Subject Knows observers, provides interface to attach/detach
Observer Defines interface for update notification
ConcreteObserver Stores reference to Subject, implements update
ConcreteSubject Stores state, sends notifications on change

24.4 πŸ’‘ Code Example

public interface Observer {
    void update(String message);
}

public class Subject {
    private List<Observer> observers = new ArrayList<>();
    
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    public void detach(Observer observer) {
        observers.remove(observer);
    }
    
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

public class ConcreteObserver implements Observer {
    private String name;
    
    @Override
    public void update(String message) {
        System.out.println(name + " received: " + message);
    }
}

// Usage
Subject subject = new Subject();
Observer obs1 = new ConcreteObserver();
subject.attach(obs1);
subject.notifyObservers("Event occurred");

Reasoning: Loose coupling between Subject and Observers; enables dynamic subscription model.


24.5 πŸ“Š Class Diagram

classDiagram
    class Subject {
        +attach(o: Observer)
        +detach(o: Observer)
        +notify()
    }
    class ConcreteSubject
    class Observer {
        <<interface>>
        +update()
    }
    class ConcreteObserver
    Subject <|-- ConcreteSubject
    Observer <|-- ConcreteObserver
    Subject --> Observer

24.6 πŸ”„ Sequence Diagram

sequenceDiagram
    participant Observer
    participant Subject
    Observer->>Subject: attach()
    Subject->>Subject: changeState()
    Subject->>Observer: notify()
    Observer->>Observer: update()

24.7 βš–οΈ Trade-offs

24.7.1 Advantages βœ…

24.7.2 Disadvantages ❌


24.8 🌍 Real-World Use Cases


24.9 πŸ“š References


25 Pipes and Filters Pattern

25.1 πŸ“‹ Overview

The Pipes and Filters pattern processes data through a series of independent, modular processing components (filters) connected by data flow channels (pipes).


25.2 🎯 Intent

Problem Solved: - Process complex workflows through independent stages - Enable modular, reusable components - Support different processing orders - Parallel and sequential processing


25.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Filter Independent processing component
Pipe Data flow channel between filters
Source Produces data
Sink Consumes final result

25.4 πŸ“Š Class Diagram

classDiagram
    class Source
    class Pipe
    class Filter {
        +process(data)
    }
    class Sink
    Source --> Pipe
    Pipe --> Filter
    Filter --> Pipe
    Pipe --> Sink

25.5 πŸ”„ Sequence Diagram

sequenceDiagram
    participant Source
    participant Pipe1
    participant Filter
    participant Pipe2
    participant Sink
    Source->>Pipe1: emit(data)
    Pipe1->>Filter: data
    Filter->>Pipe2: processed
    Pipe2->>Sink: processed

25.6 βš–οΈ Trade-offs

25.6.1 Advantages βœ…

25.6.2 Disadvantages ❌


25.7 🌍 Real-World Use Cases


25.8 πŸ“š References


26 Prototype Pattern

26.1 πŸ“‹ Overview

This folder contains the Prototype design pattern implementation.


26.2 🎯 Intent

The prototype pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.


26.3 πŸ‘₯ Roles & Responsibilities

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.


26.4 πŸ’‘ Code Example

Please see the src/ directory for complete, executable code examples demonstrating this pattern.


26.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Prototype {
        <<interface>>
        +clone()
    }
    class ConcretePrototype
    Client --> Prototype
    Prototype <|-- ConcretePrototype

26.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Prototype: clone()
    Prototype-->>Client: copy

26.7 βš–οΈ Trade-offs

26.7.1 Advantages βœ…

26.7.2 Disadvantages ❌


26.8 🚫 When NOT to Use


26.9 ⚠️ Common Anti-Patterns

Anti-Pattern Issue Solution
Overuse Using pattern unnecessarily Apply YAGNI principle
Misapplication Wrong context for pattern Study pattern requirements
Complexity Pattern makes code harder Simplify or choose different pattern

26.10 🌍 Real-World Use Cases

This pattern appears frequently in: - Enterprise applications - Framework and library design - System integration scenarios


26.11 πŸ”— Alternatives & Similar Patterns


26.12 πŸ“ Best Practices

  1. Understand the problem before applying the pattern
  2. Document your pattern usage clearly
  3. Keep implementations simple
  4. Test thoroughly
  5. Consider performance implications
  6. Review periodically for improvements
  7. Teach team members about the pattern
  8. Refactor if pattern no longer applies

26.13 πŸ“š References

For detailed implementation, see the source files in src/.


27 Proxy Pattern

27.1 πŸ“‹ Overview

This folder contains the Proxy design pattern implementation.


27.2 🎯 Intent

The proxy pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.


27.3 πŸ‘₯ Roles & Responsibilities

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.


27.4 πŸ’‘ Code Example

Please see the src/ directory for complete, executable code examples demonstrating this pattern.


27.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Subject {
        <<interface>>
        +request()
    }
    class RealSubject
    class Proxy {
        -real: RealSubject
        +request()
    }
    Client --> Subject
    Subject <|-- RealSubject
    Subject <|-- Proxy
    Proxy --> RealSubject

27.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Proxy: request()
    Proxy->>RealSubject: request()
    RealSubject-->>Proxy: result
    Proxy-->>Client: result

27.7 βš–οΈ Trade-offs

27.7.1 Advantages βœ…

27.7.2 Disadvantages ❌


27.8 🚫 When NOT to Use


27.9 ⚠️ Common Anti-Patterns

Anti-Pattern Issue Solution
Overuse Using pattern unnecessarily Apply YAGNI principle
Misapplication Wrong context for pattern Study pattern requirements
Complexity Pattern makes code harder Simplify or choose different pattern

27.10 🌍 Real-World Use Cases

This pattern appears frequently in: - Enterprise applications - Framework and library design - System integration scenarios


27.11 πŸ”— Alternatives & Similar Patterns


27.12 πŸ“ Best Practices

  1. Understand the problem before applying the pattern
  2. Document your pattern usage clearly
  3. Keep implementations simple
  4. Test thoroughly
  5. Consider performance implications
  6. Review periodically for improvements
  7. Teach team members about the pattern
  8. Refactor if pattern no longer applies

27.13 πŸ“š References

For detailed implementation, see the source files in src/.


28 Servant Pattern

28.1 πŸ“‹ Overview

The Servant pattern defines common functionality in a separate class (servant) that serves multiple classes, enabling code reuse without inheritance.


28.2 🎯 Intent

Problem Solved: - Provide common functionality to multiple unrelated classes - Avoid code duplication without inheritance - Reduce class hierarchy complexity - Enable flexible behavior sharing


28.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Servant Provides common functionality
Served Classes Use servant functionality
Client Initiates servant behavior

28.4 πŸ’‘ Implementation


28.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Servant {
        +operation(served)
    }
    class ServedA
    class ServedB
    Client --> Servant
    Servant --> ServedA
    Servant --> ServedB

28.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Servant: operation(served)
    Servant->>ServedA: doWork()
    Servant-->>Client: result

28.7 βš–οΈ Trade-offs

28.7.1 Advantages βœ…

28.7.2 Disadvantages ❌


28.8 🌍 Real-World Use Cases


28.9 πŸ“š References


29 Service Locator Pattern

29.1 πŸ“‹ Overview

The Service Locator pattern centralizes logic for creating and accessing services, providing a single point for service instantiation and discovery.


29.2 🎯 Intent

Problem Solved: - Decouple service creation from usage - Provide single service access point - Enable service substitution - Centralize service configuration


29.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
ServiceLocator Provides service access
Service Defines service interface
ServiceImpl Concrete service implementation

29.4 ⚠️ Note

Service Locator is often considered an anti-pattern. Dependency Injection is the preferred modern approach.


29.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class ServiceLocator {
        +getService(name)
    }
    class Service {
        <<interface>>
        +execute()
    }
    class ConcreteServiceA
    class ConcreteServiceB
    Client --> ServiceLocator
    Service <|-- ConcreteServiceA
    Service <|-- ConcreteServiceB
    ServiceLocator --> Service

29.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>ServiceLocator: getService(name)
    ServiceLocator-->>Client: Service
    Client->>Service: execute()

29.7 βš–οΈ Trade-offs

29.7.1 Advantages βœ…

29.7.2 Disadvantages ❌


29.8 🌍 Real-World Use Cases


29.9 πŸ“š References


30 Singleton Pattern

30.1 πŸ“‹ Overview

The Singleton Pattern ensures that a class has only one instance and provides a global point of access to it. This is a creational pattern that restricts object instantiation to a single instance while providing a mechanism to access that instance universally.


30.2 🎯 Intent

Problem Solved: - You need to guarantee that only one instance of a class exists throughout the application lifecycle - Multiple instances would cause logical errors or resource conflicts (e.g., database connections, configuration managers, logging services) - You need a globally accessible point of access to this single instance without passing references through all layers

Use When: - You need a single, shared resource manager (connection pools, thread pools, caches) - You need a centralized configuration holder or registry - You need exactly one instance of a service to coordinate system-wide activities


30.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Singleton Ensures only one instance exists via private constructor; provides static method to access the single instance
Client Accesses the singleton instance through the public static accessor method

Key Characteristics: - Private constructor prevents external instantiation - Static instance variable holds the single object - Public static accessor method (getInstance()) returns the instance - Thread-safety considerations for multi-threaded environments


30.4 πŸ’‘ Implementation Strategies

This pattern has multiple implementations, each with different trade-offs:

30.4.1 1. Eager Initialization

public class EagerInitializedSingleton {
    private static final EagerInitializedSingleton instance = 
        new EagerInitializedSingleton();
    
    private EagerInitializedSingleton() { }
    
    public static EagerInitializedSingleton getInstance() {
        return instance;
    }
}

Reasoning: Instance created when class is loaded. Thread-safe by default but allocates memory immediately.

30.4.2 2. Lazy Initialization with Synchronization

public class ThreadSafeSingleton {
    private static ThreadSafeSingleton instance;
    
    private ThreadSafeSingleton() { }
    
    public static synchronized ThreadSafeSingleton getInstance() {
        if (instance == null) {
            instance = new ThreadSafeSingleton();
        }
        return instance;
    }
}

Reasoning: Creates instance on first use. Synchronized method ensures thread-safety but causes synchronization overhead on every call.

30.4.3 3. Double-Checked Locking

public class ThreadSafeSingleton {
    private static ThreadSafeSingleton instance;
    
    private ThreadSafeSingleton() { }
    
    public static ThreadSafeSingleton getInstance() {
        if (instance == null) {
            synchronized (ThreadSafeSingleton.class) {
                if (instance == null) {
                    instance = new ThreadSafeSingleton();
                }
            }
        }
        return instance;
    }
}

Reasoning: Checks instance twiceβ€”once outside lock, once inside. Reduces synchronization overhead while ensuring thread-safety.

30.4.4 4. Bill Pugh Singleton (Class Loader)

public class BillPughSingleton {
    private BillPughSingleton() { }
    
    private static class SingletonHelper {
        private static final BillPughSingleton instance = 
            new BillPughSingleton();
    }
    
    public static BillPughSingleton getInstance() {
        return SingletonHelper.instance;
    }
}

Reasoning: Uses inner class to achieve lazy initialization. Thread-safe by design and efficient (no synchronization overhead).


30.5 πŸ“Š Class Diagram

classDiagram
    class Client
    class Singleton {
        -static instance: Singleton
        +getInstance(): Singleton
    }
    Client --> Singleton

30.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Singleton: getInstance()
    Singleton-->>Client: instance

30.7 πŸ”€ Design Principles Emphasized

Principle How Applied
Single Responsibility Singleton class has one job: manage the single instance
Dependency Inversion Clients depend on the abstraction (interface) rather than concrete class
Separation of Concerns Instance management is separated from business logic
Composition over Inheritance Rather than subclassing, dependency is injected or accessed via static method

30.8 βš–οΈ Trade-offs

30.8.1 Advantages βœ…

30.8.2 Disadvantages ❌


30.9 🚫 When NOT to Use

Scenario Why Avoid
Stateful Objects Sharing state across all clients leads to unexpected side effects
Testable Systems Global dependencies make unit testing extremely difficult
Multiple Instances Needed If business logic later requires multiple instances, refactoring is painful
Distributed Systems Each JVM/process gets its own instance; doesn’t guarantee global uniqueness
Simple Services Dependency Injection (DI) containers provide same benefits with better flexibility

30.10 ⚠️ Common Anti-Patterns & Misuses

Anti-Pattern Problem Solution
Mutable Singleton Shared state gets corrupted by concurrent modifications Make singleton immutable or use thread-safe collections
Singleton as Service Locator Hides dependencies and couples code to singleton Use constructor injection instead
Testing Without Mock/Spy Tests affect each other via shared state Provide reset method or use test-specific implementations
Singleton Inheritance Each subclass becomes a different singleton Use composition; wrap the actual singleton
Unnecessary Singletons Over-use creates tight coupling Prefer dependency injection via constructors
Non-Thread-Safe Singleton Race conditions in multi-threaded apps Use double-checked locking or eager initialization

30.11 🌍 Real-World Use Cases

30.11.1 Spring Framework

// Spring beans are singletons by default
@Service
public class UserService {
    // Only one instance in Spring Container
}

// Access via Dependency Injection
@Component
public class UserController {
    @Autowired
    private UserService userService;  // Singleton instance injected
}

30.11.2 Log4j / SLF4J

// Logger is typically a singleton
Logger logger = LoggerFactory.getLogger(MyClass.class);
// Returns same logger instance for same class name

30.11.3 Database Connection Pool

// ConnectionPool as singleton to manage all connections
public class ConnectionPool {
    private static final ConnectionPool instance = new ConnectionPool();
    
    public static ConnectionPool getInstance() {
        return instance;
    }
}

30.11.4 Configuration Manager

// Singleton holding application configuration
public class AppConfig {
    private static final AppConfig instance = new AppConfig();
    
    public String getDatabaseUrl() { /* ... */ }
    public int getMaxConnections() { /* ... */ }
}

30.12 πŸ”— Alternatives & Similar Patterns

Alternative When to Prefer
Dependency Injection When using a DI container (Spring, Guice); provides testability and flexibility
Static Class For stateless utilities; simpler than singleton but can’t implement interfaces
Enum Singleton For thread-safety and serialization guarantees in Java
Factory Pattern When you need flexibility to create different implementations
Service Locator When you need dynamic service registration (though often considered an anti-pattern)

30.13 πŸ“ Best Practices

  1. Prefer Dependency Injection: Use DI container (Spring, Guice) instead of manual singleton management
  2. Make Thread-Safe: Use Bill Pugh Singleton or eager initialization for multi-threaded applications
  3. Document Constraints: Clearly state that your class is a singleton and why
  4. Provide Test Hooks: Add methods to reset state for testing
  5. Avoid Mutable State: Keep singleton data immutable or use thread-safe collections
  6. Consider Enum Singleton: In Java, enum provides the most robust singleton implementation
  7. Avoid as Service Locator: Don’t use singleton to hide dependencies; use dependency injection


30.15 πŸ“š References


31 State Machine Pattern

31.1 πŸ“‹ Overview

The State Machine pattern models complex workflows and state transitions using explicit state objects and transitions.


31.2 🎯 Intent

Problem Solved: - Model complex workflows with multiple states - Manage state transitions - Enforce valid state transitions - Handle state-dependent behavior


31.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
State Defines state interface
ConcreteState Implements state-specific behavior
StateMachine Context managing states

31.4 πŸ’‘ Implementation


31.5 πŸ“Š Class Diagram

classDiagram
    class StateMachine {
        -current: State
        +handle(event)
    }
    class State {
        <<interface>>
        +onEvent(event)
    }
    class ConcreteStateA
    class ConcreteStateB
    class Event
    StateMachine --> State
    State <|-- ConcreteStateA
    State <|-- ConcreteStateB
    StateMachine --> Event

31.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>StateMachine: handle(event)
    StateMachine->>State: onEvent(event)
    State-->>StateMachine: nextState
    StateMachine-->>Client: transitioned

31.7 βš–οΈ Trade-offs

31.7.1 Advantages βœ…

31.7.2 Disadvantages ❌


31.8 🌍 Real-World Use Cases


31.9 πŸ“š References


32 State Pattern

32.1 πŸ“‹ Overview

The State pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.


32.2 🎯 Intent

Problem Solved: - Object behavior varies based on state - Large conditional statements checking state - State transitions need management


32.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Context Defines interface, delegates to State
State Defines interface for state-specific behavior
ConcreteState Implements state-specific behavior

32.4 πŸ’‘ Code Example

public interface State {
    void handle(Context context);
}

public class Context {
    private State state;
    
    public Context(State state) {
        this.state = state;
    }
    
    public void setState(State state) {
        this.state = state;
    }
    
    public void request() {
        state.handle(this);
    }
}

public class ConcreteStateA implements State {
    @Override
    public void handle(Context context) {
        System.out.println("State A handling");
        context.setState(new ConcreteStateB());
    }
}

// Usage
Context context = new Context(new ConcreteStateA());
context.request();
context.request();

Reasoning: Encapsulates state-dependent behavior; enables state-specific transitions.


32.5 πŸ“Š Class Diagram

classDiagram
    class Context {
        -state: State
        +request()
        +setState(s: State)
    }
    class State {
        <<interface>>
        +handle(ctx: Context)
    }
    class ConcreteStateA
    class ConcreteStateB
    Context --> State
    State <|-- ConcreteStateA
    State <|-- ConcreteStateB

32.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Context: request()
    Context->>State: handle(context)
    State-->>Context: maybe change state

32.7 βš–οΈ Trade-offs

32.7.1 Advantages βœ…

32.7.2 Disadvantages ❌


32.8 🌍 Real-World Use Cases


32.9 πŸ“š References


33 Strategy Pattern

33.1 πŸ“‹ Overview

The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable.


33.2 🎯 Intent

Problem Solved: - Multiple algorithms for a task - Algorithm selection varies - Avoid large conditional statements


33.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Strategy Defines interface for algorithm
ConcreteStrategy Implements specific algorithm
Context Uses Strategy

33.4 πŸ’‘ Code Example

public interface SortStrategy {
    void sort(int[] array);
}

public class Context {
    private SortStrategy strategy;
    
    public void setStrategy(SortStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void executeSort(int[] array) {
        strategy.sort(array);
    }
}

public class QuickSort implements SortStrategy {
    @Override
    public void sort(int[] array) {
        // QuickSort implementation
    }
}

// Usage
Context context = new Context();
context.setStrategy(new QuickSort());
context.executeSort(array);

Reasoning: Encapsulates algorithms; enables runtime selection; promotes composition.


33.5 πŸ“Š Class Diagram

classDiagram
    class Context {
        -strategy: Strategy
        +setStrategy(s: Strategy)
        +execute()
    }
    class Strategy {
        <<interface>>
        +algorithm()
    }
    class ConcreteStrategyA
    class ConcreteStrategyB
    Context --> Strategy
    Strategy <|-- ConcreteStrategyA
    Strategy <|-- ConcreteStrategyB

33.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Context: setStrategy(strategy)
    Client->>Context: execute()
    Context->>Strategy: algorithm()

33.7 βš–οΈ Trade-offs

33.7.1 Advantages βœ…

33.7.2 Disadvantages ❌


33.8 🌍 Real-World Use Cases


33.9 πŸ“š References


34 Template Method Pattern

34.1 πŸ“‹ Overview

The Template Method pattern defines the skeleton of an algorithm in a base class, letting subclasses override specific steps.


34.2 🎯 Intent

Problem Solved: - Algorithm structure is fixed, but steps vary - Avoid code duplication in algorithm implementations - Control subclass overrides


34.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
AbstractClass Defines template method and steps
ConcreteClass Implements specific steps

34.4 πŸ’‘ Code Example

public abstract class DataProcessor {
    public final void process() {
        readData();
        validateData();
        processData();
        writeData();
    }
    
    abstract void readData();
    abstract void validateData();
    abstract void processData();
    abstract void writeData();
}

public class XMLProcessor extends DataProcessor {
    @Override
    void readData() { /* XML reading */ }
    
    @Override
    void validateData() { /* XML validation */ }
    
    @Override
    void processData() { /* XML processing */ }
    
    @Override
    void writeData() { /* XML writing */ }
}

// Usage
DataProcessor processor = new XMLProcessor();
processor.process();

Reasoning: Defines algorithm structure; lets subclasses implement steps; prevents duplication.


34.5 πŸ“Š Class Diagram

classDiagram
    class AbstractClass {
        +templateMethod()
        #primitiveOp1()
        #primitiveOp2()
    }
    class ConcreteClass
    AbstractClass <|-- ConcreteClass

34.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>AbstractClass: templateMethod()
    AbstractClass->>AbstractClass: primitiveOp1()
    AbstractClass->>AbstractClass: primitiveOp2()
    AbstractClass-->>Client: done

34.7 βš–οΈ Trade-offs

34.7.1 Advantages βœ…

34.7.2 Disadvantages ❌


34.8 🌍 Real-World Use Cases


34.9 πŸ“š References


35 Visitor Pattern

35.1 πŸ“‹ Overview

The Visitor pattern represents an operation to be performed on elements of an object structure. It lets you define a new operation without changing the classes of the elements on which it operates.


35.2 🎯 Intent

Problem Solved: - Perform operations on complex object structures without changing their classes - Add new operations to class hierarchy without modification - Operations are related but scattered across classes


35.3 πŸ‘₯ Roles & Responsibilities

Role Responsibility
Visitor Declares visit methods for each element type
ConcreteVisitor Implements specific operations
Element Accepts visitor
ConcreteElement Implements accept method
ObjectStructure Provides access to elements

35.4 πŸ’‘ Implementation

Visitor pattern is particularly useful when you have: - Complex object hierarchies requiring multiple operations - Operations that change frequently - Classes that shouldn’t be modified with new methods - Need to gather data from object structure


35.5 πŸ“Š Class Diagram

classDiagram
    class Visitor {
        <<interface>>
        +visitConcreteElementA(e)
        +visitConcreteElementB(e)
    }
    class ConcreteVisitor
    class Element {
        <<interface>>
        +accept(v: Visitor)
    }
    class ConcreteElementA
    class ConcreteElementB
    Visitor <|-- ConcreteVisitor
    Element <|-- ConcreteElementA
    Element <|-- ConcreteElementB
    Element --> Visitor

35.6 πŸ”„ Sequence Diagram

sequenceDiagram
    actor Client
    Client->>Element: accept(visitor)
    Element->>Visitor: visit(element)

35.7 βš–οΈ Trade-offs

35.7.1 Advantages βœ…

35.7.2 Disadvantages ❌


35.8 🌍 Real-World Use Cases


35.9 πŸ“š References