CodeToConcept
About

java

java Tutorials

Introduction
Java Variables
Java Data Types
Java Type Casting
Java Operators
Java Input/Output
Java Class & Object
java Method
Java Constructor
Java this keyword
Java super keyword
Java Method Overloading and Overriding
Java Interface
Java Abstract Class
Java Memory Management
Design Patterns
JDBC (Database Connectivity)
Java IDEs

java Tutorials

Introduction
Java Variables
Java Data Types
Java Type Casting
Java Operators
Java Input/Output
Java Class & Object
java Method
Java Constructor
Java this keyword
Java super keyword
Java Method Overloading and Overriding
Java Interface
Java Abstract Class
Java Memory Management
Design Patterns
JDBC (Database Connectivity)
Java IDEs

Sample Question

Think it through, then check the tutorial.

CodeToConcept

Quickly learn through simple, structured, and practical coding tutorials. Build your confidence from step zero to real-world experience.

© 2026 CodeToConcept. All rights reserved.

Quick Links

AboutTutorials

Tutorials

JavaHTMLCSS

Support

Privacy PolicyTerms of ServiceContact
GitHubTwitterYouTube

Java Design Patterns

Run each complete program separately. Its required helper classes and imports are included in the same code block. Short syntax fragments explain individual operations.

A design pattern names a useful way to arrange responsibilities when a design problem keeps recurring. For example, a caller may need to swap a behavior without editing its own control flow. Patterns help discuss such choices, but each choice still needs a reason in the actual application.

A design pattern is not a ready-made piece of code. Instead, it provides a proven approach for structuring classes and objects to solve a particular type of problem.

Design patterns help developers create software that is easier to:

  • Understand
  • Maintain
  • Extend
  • Test
  • Reuse

What is a Design Pattern?

A design pattern is a general design solution that can be applied to a recurring problem in software development.

For example, suppose an application should have only one instance of a particular class.

Instead of designing the solution from scratch, we can use the Singleton pattern.

Similarly, if an object should be created without exposing complicated creation logic to the client, patterns such as Factory or Builder can be useful.

Why Do We Need Design Patterns?

As applications become larger, simply writing classes and methods is not enough.

We need to decide:

  • Which class should create an object?
  • Which class should be responsible for a particular operation?
  • How should objects communicate?
  • How can we avoid tightly coupled code?
  • How can we make the code easier to extend?

Design patterns provide commonly recognized approaches to these problems.

Simple Example

Suppose we have:

class EmailService {
    public void sendEmail() {
        System.out.println("Sending email");
    }
}

Another class directly creates it:

class NotificationService {
 
    private EmailService emailService =
        new EmailService();
 
    public void notifyUser() {
        emailService.sendEmail();
    }
}

This creates a strong dependency between NotificationService and EmailService.

A better design may introduce an abstraction:

interface Notification {
    void send();
}

Now different implementations can be created:

class EmailNotification implements Notification {
 
    public void send() {
        System.out.println("Sending email");
    }
}

The exact pattern used depends on the problem we are trying to solve.

Categories of Design Patterns

Design patterns are commonly divided into three major categories:

                 Design Patterns
                       |
          +------------+------------+
          |            |            |
     Creational   Structural   Behavioral

1. Creational Patterns

Deal with object creation.

Examples:

  • Singleton
  • Factory Method
  • Abstract Factory
  • Builder
  • Prototype

2. Structural Patterns

Deal with how classes and objects are organized and combined.

Examples:

  • Adapter
  • Bridge
  • Composite
  • Decorator
  • Facade
  • Flyweight
  • Proxy

3. Behavioral Patterns

Deal with communication and responsibilities between objects.

Examples:

  • Chain of Responsibility
  • Command
  • Iterator
  • Mediator
  • Memento
  • Observer
  • State
  • Strategy
  • Template Method
  • Visitor

1. Singleton Pattern

The Singleton pattern ensures that a class has only one instance and provides a way to access that instance.

Example

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

Usage:

class DatabaseConnection {
 
    private static DatabaseConnection instance;
 
    private DatabaseConnection() {
    }
 
    public static DatabaseConnection getInstance() {
 
        if (instance == null) {
            instance = new DatabaseConnection();
        }
 
        return instance;
    }
}
 
public class HelloWorld {
 
    public static void main(String[] args) {
 
        DatabaseConnection obj1 =
            DatabaseConnection.getInstance();
 
        DatabaseConnection obj2 =
            DatabaseConnection.getInstance();
 
        System.out.println(obj1 == obj2);
    }
}

Output

true

Both variables refer to the same object.

Important Point

Singleton implementations require careful consideration in multithreaded applications. A simple lazy implementation like the above is not thread-safe.

2. Factory Method Pattern

The Factory Method pattern puts an object-creation method in a parent type and lets subclasses choose the concrete product. The static selection example below is a Simple Factory, a related creation technique rather than the subclass-based Factory Method pattern.

Example

interface Vehicle {
    void drive();
}

Implementations:

class Car implements Vehicle {
 
    public void drive() {
        System.out.println("Driving a car");
    }
}
class Bike implements Vehicle {
 
    public void drive() {
        System.out.println("Riding a bike");
    }
}

Factory:

class VehicleFactory {
 
    public static Vehicle createVehicle(String type) {
 
        if (type.equalsIgnoreCase("car")) {
            return new Car();
        }
 
        if (type.equalsIgnoreCase("bike")) {
            return new Bike();
        }
 
        throw new IllegalArgumentException(
            "Unknown vehicle type"
        );
    }
}

Usage:

class Bike implements Vehicle {
 
    public void drive() {
        System.out.println("Riding a bike");
    }
}
 
class Car implements Vehicle {
 
    public void drive() {
        System.out.println("Driving a car");
    }
}
 
class VehicleFactory {
 
    public static Vehicle createVehicle(String type) {
 
        if (type.equalsIgnoreCase("car")) {
            return new Car();
        }
 
        if (type.equalsIgnoreCase("bike")) {
            return new Bike();
        }
 
        throw new IllegalArgumentException(
            "Unknown vehicle type"
        );
    }
}
 
interface Vehicle {
    void drive();
}
 
public class HelloWorld {
 
    public static void main(String[] args) {
 
        Vehicle vehicle =
            VehicleFactory.createVehicle("car");
 
        vehicle.drive();
    }
}

Output

Driving a car

The client does not directly create the Car object.

Factory Method Through a Subclass

Here ReportCreator defines the workflow and calls createReport(). DailyReportCreator chooses the report implementation by overriding that method. Each block is a separate example; it does not replace the Simple Factory shown above.

interface Report {
    String title();
}
 
class DailyReport implements Report {
    public String title() {
        return "Daily reading summary";
    }
}
 
abstract class ReportCreator {
    abstract Report createReport();
 
    void printTitle() {
        System.out.println(createReport().title());
    }
}
 
class DailyReportCreator extends ReportCreator {
    @Override
    Report createReport() {
        return new DailyReport();
    }
}
 
public class HelloWorld {
    public static void main(String[] args) {
        ReportCreator creator = new DailyReportCreator();
        creator.printTitle();
    }
}

Output:

Daily reading summary

3. Abstract Factory Pattern

The Abstract Factory pattern provides an interface for creating families of related objects without specifying their concrete classes.

For example, suppose an application supports different UI themes:

Dark Theme
 ├── DarkButton
 └── DarkCheckbox
 
Light Theme
 ├── LightButton
 └── LightCheckbox

The factory can create a matching set of objects.

This pattern is useful when objects need to work together as a family.

4. Builder Pattern

The Builder pattern is useful for creating complex objects step by step.

Suppose a Student object has many optional properties.

class Student {
 
    private String name;
    private int age;
    private String email;
 
    private Student(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.email = builder.email;
    }
 
    static class Builder {
 
        private String name;
        private int age;
        private String email;
 
        Builder setName(String name) {
            this.name = name;
            return this;
        }
 
        Builder setAge(int age) {
            this.age = age;
            return this;
        }
 
        Builder setEmail(String email) {
            this.email = email;
            return this;
        }
 
        Student build() {
            return new Student(this);
        }
    }
}

Usage:

Student student =
    new Student.Builder()
        .setName("Rahul")
        .setAge(20)
        .setEmail("rahul@example.com")
        .build();

The builder makes object construction easier to read.

5. Prototype Pattern

The Prototype pattern creates new objects by copying an existing object.

Conceptually:

Existing Object
      |
      | copy
      ↓
New Object

A common Java approach is to provide a copy constructor or another explicit copying mechanism.

Example

class Student {
 
    private String name;
 
    Student(String name) {
        this.name = name;
    }
 
    Student(Student other) {
        this.name = other.name;
    }
}

Usage:

Student original =
    new Student("Rahul");
 
Student copy =
    new Student(original);

Structural Design Patterns

Structural patterns focus on relationships between classes and objects.

6. Adapter Pattern

The Adapter pattern allows incompatible interfaces to work together.

For example:

Client
  ↓
Adapter
  ↓
Existing Class

Example

interface PaymentProcessor {
    void pay();
}

Existing class:

class OldPaymentSystem {
 
    public void makePayment() {
        System.out.println(
            "Payment completed"
        );
    }
}

Adapter:

class PaymentAdapter
        implements PaymentProcessor {
 
    private OldPaymentSystem oldSystem;
 
    PaymentAdapter(OldPaymentSystem oldSystem) {
        this.oldSystem = oldSystem;
    }
 
    public void pay() {
        oldSystem.makePayment();
    }
}

Usage:

PaymentProcessor processor =
    new PaymentAdapter(
        new OldPaymentSystem()
    );
 
processor.pay();

Output

Payment completed

The adapter allows the old system to work with the new interface.

7. Decorator Pattern

The Decorator pattern adds additional behavior to an object without modifying its original class.

Example

Basic Coffee
     ↓
Coffee + Milk
     ↓
Coffee + Milk + Sugar

Java example:

interface Coffee {
    String getDescription();
}

Basic implementation:

class BasicCoffee implements Coffee {
 
    public String getDescription() {
        return "Coffee";
    }
}

Decorator:

class MilkDecorator implements Coffee {
 
    private Coffee coffee;
 
    MilkDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
 
    public String getDescription() {
        return coffee.getDescription()
             + " + Milk";
    }
}

Usage:

Coffee coffee =
    new MilkDecorator(
        new BasicCoffee()
    );
 
System.out.println(
    coffee.getDescription()
);

Output

Coffee + Milk

8. Facade Pattern

The Facade pattern provides a simple interface over a complex subsystem.

Suppose an order process requires:

Inventory
Payment
Shipping
Notification

Instead of the client interacting with all these systems, we can create a facade.

class OrderFacade {
 
    public void placeOrder() {
 
        System.out.println("Checking inventory");
        System.out.println("Processing payment");
        System.out.println("Creating shipment");
        System.out.println("Sending notification");
    }
}

Client:

OrderFacade facade =
    new OrderFacade();
 
facade.placeOrder();

Output

Checking inventory
Processing payment
Creating shipment
Sending notification

The facade hides the subsystem complexity from the client.

9. Proxy Pattern

The Proxy pattern provides a substitute or representative object that controls access to another object.

Client
  ↓
Proxy
  ↓
Real Object

A proxy can be used for:

  • Access control
  • Lazy initialization
  • Logging
  • Caching
  • Remote communication

Example

interface Image {
    void display();
}

Real object:

class RealImage implements Image {
 
    public RealImage() {
        System.out.println("Loading image");
    }
 
    public void display() {
        System.out.println("Displaying image");
    }
}

Proxy:

class ImageProxy implements Image {
 
    private RealImage image;
 
    public void display() {
 
        if (image == null) {
            image = new RealImage();
        }
 
        image.display();
    }
}

The proxy delays creation of the real object until it is actually needed.

Behavioral Design Patterns

Behavioral patterns focus on communication and responsibilities between objects.

10. Strategy Pattern

The Strategy pattern allows different algorithms or behaviors to be selected at runtime.

For example, a payment system may support:

Credit Card
UPI
Bank Transfer

Define an interface:

interface PaymentStrategy {
    void pay(double amount);
}

Implementation:

class CardPayment implements PaymentStrategy {
 
    public void pay(double amount) {
        System.out.println(
            "Paid using card: " + amount
        );
    }
}

Another implementation:

class UpiPayment implements PaymentStrategy {
 
    public void pay(double amount) {
        System.out.println(
            "Paid using UPI: " + amount
        );
    }
}

Context:

class PaymentService {
 
    private PaymentStrategy strategy;
 
    PaymentService(PaymentStrategy strategy) {
        this.strategy = strategy;
    }
 
    public void makePayment(double amount) {
        strategy.pay(amount);
    }
}

Usage:

PaymentService service =
    new PaymentService(
        new UpiPayment()
    );
 
service.makePayment(500);

Output

Paid using UPI: 500.0

The payment behavior can be changed without changing PaymentService.

11. Observer Pattern

The Observer pattern establishes a relationship where multiple objects are notified when the state of another object changes.

Example

Subject
  |
  +---- Observer 1
  |
  +---- Observer 2
  |
  +---- Observer 3

A common real-world concept is notification.

For example, when an event occurs, multiple subscribers may need to receive an update.

12. Command Pattern

The Command pattern encapsulates an operation as an object.

Instead of directly performing an operation:

light.turnOn();

we can represent the action as a command.

Conceptually:

Command
   ↓
execute()
   ↓
Receiver

This can be useful for:

  • Undo/redo
  • Queuing operations
  • Logging actions
  • Scheduling operations

13. Iterator Pattern

The Iterator pattern provides a standard way to traverse elements of a collection without exposing its internal structure.

Java collections already provide iterator support.

Example

import java.util.*;
 
public class HelloWorld {
 
    public static void main(String[] args) {
 
        List<String> names =
            Arrays.asList(
                "Rahul",
                "Priya",
                "Amit"
            );
 
        Iterator<String> iterator =
            names.iterator();
 
        while (iterator.hasNext()) {
            System.out.println(
                iterator.next()
            );
        }
    }
}

Output

Rahul
Priya
Amit

14. Template Method Pattern

The Template Method pattern defines the overall structure of an algorithm while allowing subclasses to customize particular steps.

Example

abstract class DataProcessor {
 
    public final void process() {
 
        readData();
        processData();
        saveData();
    }
 
    abstract void readData();
 
    abstract void processData();
 
    void saveData() {
        System.out.println("Saving data");
    }
}

The algorithm remains:

readData()
    ↓
processData()
    ↓
saveData()

Subclasses can provide their own implementations of the required steps.

15. Chain of Responsibility Pattern

The Chain of Responsibility pattern passes a request through a sequence of handlers.

Request
   ↓
Handler 1
   ↓
Handler 2
   ↓
Handler 3

Each handler can:

  • Process the request
  • Pass it to the next handler

This pattern is useful when multiple objects may be capable of handling a request.

16. State Pattern

The State pattern allows an object to change its behavior when its internal state changes.

For example, an order might have states:

NEW
 ↓
CONFIRMED
 ↓
SHIPPED
 ↓
DELIVERED

The behavior of the order can depend on its current state.

Design Pattern Summary

CategoryPatternMain Purpose
CreationalSingletonOne shared instance
CreationalFactory MethodEncapsulate object creation
CreationalAbstract FactoryCreate related object families
CreationalBuilderBuild complex objects step by step
CreationalPrototypeCreate objects by copying
StructuralAdapterMake incompatible interfaces work together
StructuralBridgeSeparate abstraction from implementation
StructuralCompositeTreat individual and group objects uniformly
StructuralDecoratorAdd behavior dynamically
StructuralFacadeSimplify a complex subsystem
StructuralFlyweightShare reusable object state
StructuralProxyControl access to another object
BehavioralChain of ResponsibilityPass requests through handlers
BehavioralCommandEncapsulate an operation
BehavioralIteratorTraverse a collection
BehavioralMediatorCentralize object communication
BehavioralMementoSave and restore object state
BehavioralObserverNotify dependent objects
BehavioralStateChange behavior based on state
BehavioralStrategySelect an algorithm/behavior
BehavioralTemplate MethodDefine an algorithm skeleton
BehavioralVisitorAdd operations without changing object structures

Design Patterns and SOLID Principles

Design patterns and SOLID principles are related, but they are not the same thing.

SOLID

SOLID provides general principles for designing maintainable object-oriented software.

Examples:

S → Single Responsibility Principle
O → Open/Closed Principle
L → Liskov Substitution Principle
I → Interface Segregation Principle
D → Dependency Inversion Principle

Design Patterns

Design patterns provide reusable approaches to particular recurring design problems.

For example:

SOLID Principles
       ↓
Good Object-Oriented Design
       ↓
Design Patterns
       ↓
Reusable Design Solutions

Design Patterns and Interfaces

Many Java design patterns make heavy use of:

  • Interfaces
  • Abstract classes
  • Inheritance
  • Composition
  • Polymorphism
  • Encapsulation

For example, the Strategy pattern uses an interface:

interface PaymentStrategy {
    void pay(double amount);
}

Different classes can implement the interface:

class CardPayment implements PaymentStrategy {
    // ...
}
 
class UpiPayment implements PaymentStrategy {
    // ...
}

This allows the application to work with the abstraction rather than a specific implementation.

Composition Over Inheritance

Many design patterns favor composition over unnecessary inheritance.

For example:

class PaymentService {
 
    private PaymentStrategy strategy;
 
    PaymentService(PaymentStrategy strategy) {
        this.strategy = strategy;
    }
}

Here, PaymentService contains a PaymentStrategy rather than inheriting from it.

This allows the strategy to be replaced easily.

Advantages of Design Patterns

1. Reusable Solutions

Patterns provide established approaches to recurring design problems.

2. Better Maintainability

Well-structured code can be easier to understand and modify.

3. Loose Coupling

Many patterns help reduce unnecessary dependencies between classes.

4. Better Communication

Developers can communicate using common terms.

For example:

"Use a Strategy here."

A developer familiar with the pattern immediately understands the general design idea.

5. Extensibility

Some patterns make it easier to add new behavior without modifying existing code extensively.

Disadvantages of Design Patterns

Design patterns are useful, but they should not be applied unnecessarily.

1. Increased Complexity

A simple problem can become unnecessarily complicated if too many abstractions are introduced.

2. More Classes

Some patterns require additional interfaces, classes, or objects.

3. Overengineering

Using a pattern simply because it is available can make code harder to understand.

4. Learning Curve

Developers need to understand the problem and the pattern before applying it effectively.

Common Mistakes

1. Using a Pattern Everywhere

Not every problem requires a design pattern.

First understand the problem, then determine whether a pattern provides a useful solution.

2. Confusing Design Pattern with Framework

A design pattern is a reusable design approach.

A framework is a software platform that provides reusable infrastructure and structure for application development.

They are different concepts.

3. Memorizing Patterns Without Understanding the Problem

Knowing the names of patterns is less useful than understanding:

Problem
   ↓
Why does it occur?
   ↓
What design can solve it?
   ↓
Which pattern fits?

4. Treating Patterns as Fixed Code

A pattern is not a code template that must always be copied exactly.

The implementation can vary depending on the application's requirements.

How to Learn Java Design Patterns

A good learning approach is:

OOP Concepts
    ↓
SOLID Principles
    ↓
Design Principles
    ↓
Creational Patterns
    ↓
Structural Patterns
    ↓
Behavioral Patterns
    ↓
Real-World Applications

Before learning design patterns, it is useful to understand:

  • Classes and objects
  • Encapsulation
  • Inheritance
  • Polymorphism
  • Interfaces
  • Abstract classes
  • Composition
  • Association
  • Aggregation
  • Exception handling
  • Generics

Important Design Patterns to Learn First

For Java developers, commonly encountered patterns include:

Singleton
Factory
Builder
Adapter
Decorator
Facade
Proxy
Strategy
Observer
Command
Template Method
Chain of Responsibility

The order in which you learn them is less important than understanding the problem each pattern addresses.

Quick Revision

Design Pattern
      ↓
Reusable design approach
      ↓
Recurring software design problem

Three major categories:

Creational
   ↓
Object creation
 
Structural
   ↓
Class/Object structure
 
Behavioral
   ↓
Object communication and behavior

Examples:

Creational
→ Singleton
→ Factory
→ Builder
→ Prototype
 
Structural
→ Adapter
→ Decorator
→ Facade
→ Proxy
 
Behavioral
→ Strategy
→ Observer
→ Command
→ Iterator
→ State
→ Template Method

Key Points

  • A design pattern is a reusable approach to a recurring software design problem.
  • A design pattern is not a ready-made piece of code.
  • Design patterns are commonly categorized as Creational, Structural, and Behavioral.
  • Creational patterns focus on object creation.
  • Structural patterns focus on relationships and object/class composition.
  • Behavioral patterns focus on communication and responsibilities.
  • Singleton deals with controlled single-instance creation.
  • Factory patterns encapsulate object creation.
  • Builder helps construct complex objects.
  • Adapter connects incompatible interfaces.
  • Decorator adds behavior without modifying the original class.
  • Facade simplifies access to complex subsystems.
  • Proxy controls access to another object.
  • Strategy allows behavior or algorithms to be changed.
  • Observer supports notification between objects.
  • Command represents an operation as an object.
  • Iterator provides a way to traverse collections.
  • Design patterns should solve real design problems rather than being added unnecessarily.

Conclusion

Java design patterns provide commonly used approaches for solving recurring software design problems.

The three major categories are:

Creational → Object Creation
Structural → Object/Class Structure
Behavioral → Object Communication

The most important lesson is not to memorize every pattern. Instead, understand the problem a pattern solves, how it works, and when it is appropriate to use it.

Good Java design combines OOP concepts, SOLID principles, composition, interfaces, and appropriate design patterns to create software that is easier to maintain and extend.

See you in next page....🙂

← Java Memory ManagementJDBC (Database Connectivity) →
← Java Memory ManagementJDBC (Database Connectivity) →