Design Patterns

Java 15 min min read Updated: Mar 31, 2026 Advanced
Design Patterns
Advanced Topic 25 of 25

Design Patterns

In software development, many problems repeat again and again. Over time, developers realized that certain types of solutions work well for certain recurring design problems. These standard, reusable solutions are called design patterns.

Design patterns do not provide ready-made code that you simply copy and paste. Instead, they provide proven design structures and best practices that help in building flexible, maintainable, and reusable software systems. In Java, design patterns are extremely important because object-oriented programming and framework-based development rely heavily on them.

Key Concept: A design pattern is a standard, reusable solution to a common software design problem. It helps improve code structure, flexibility, maintainability, and reusability.

What are Design Patterns?

Design patterns are general solutions to recurring software design problems. They are not full applications or complete code modules. Instead, they are templates or strategies for solving common object-oriented design issues.

For example:

  • How to ensure only one object of a class exists?
  • How to create objects without tightly coupling the client to specific classes?
  • How to notify multiple objects when one object changes?
  • How to change behavior dynamically without modifying code structure?

Design patterns answer such questions using well-structured approaches.

Why Design Patterns are Important

  • improve code reusability
  • reduce code duplication
  • support loose coupling
  • improve maintainability
  • make communication easier between developers
  • provide proven solutions to common problems

If a developer says, β€œUse Factory Pattern here,” experienced team members immediately understand the intended design style.

History of Design Patterns

Design patterns became widely known through the famous book:

Design Patterns: Elements of Reusable Object-Oriented Software

written by the β€œGang of Four” (GoF):

  • Erich Gamma
  • Richard Helm
  • Ralph Johnson
  • John Vlissides

Because of this, many classic design patterns are called GoF design patterns.

Main Categories of Design Patterns

Design patterns are usually grouped into three main categories:

  • Creational patterns
  • Structural patterns
  • Behavioral patterns

1. Creational Design Patterns

Creational patterns deal with object creation mechanisms. They help make object creation more flexible and less tightly coupled.

Common creational patterns:

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

2. Structural Design Patterns

Structural patterns deal with class and object composition. They help build relationships between objects in a flexible way.

Common structural patterns:

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

3. Behavioral Design Patterns

Behavioral patterns deal with communication and interaction between objects.

Common behavioral patterns:

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

Most Important Design Patterns for Java Beginners and Interviews

While there are many patterns, some are especially important in Core Java and interviews:

  • Singleton Pattern
  • Factory Pattern
  • Builder Pattern
  • Adapter Pattern
  • Decorator Pattern
  • Observer Pattern
  • Strategy Pattern

Singleton Pattern

Singleton Pattern ensures that only one object of a class is created and provides a global access point to that object.

It is useful when a class should have only one shared instance, such as:

  • configuration manager
  • database connection manager
  • logging service

Basic Singleton Example

java class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }

Important points:

  • constructor is private
  • object is created once
  • access is given through getInstance()

Using Singleton

java public class Main { public static void main(String[] args) { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); System.out.println(s1 == s2); } }

Output will be:

text true

This proves both references point to the same object.

Factory Pattern

Factory Pattern is used when object creation logic should be separated from the client code. Instead of creating objects directly with new, the client asks a factory to create the required object.

This reduces coupling between client code and concrete classes.

Example Without Factory

java Dog d = new Dog();

Here, the client directly depends on the Dog class.

Factory Pattern Example

java interface Animal { void sound(); } class Dog implements Animal { public void sound() { System.out.println("Dog barks"); } } class Cat implements Animal { public void sound() { System.out.println("Cat meows"); } } class AnimalFactory { Animal getAnimal(String type) { if (type.equalsIgnoreCase("dog")) { return new Dog(); } else if (type.equalsIgnoreCase("cat")) { return new Cat(); } return null; } }

Using Factory

java public class Main { public static void main(String[] args) { AnimalFactory factory = new AnimalFactory(); Animal a = factory.getAnimal("dog"); a.sound(); } }

This makes object creation more flexible.

Builder Pattern

Builder Pattern is useful when an object has many fields and creating it using constructors becomes confusing or unreadable.

It is especially useful when:

  • many constructor parameters exist
  • some parameters are optional
  • readability is important

Problem Without Builder

java Student s = new Student("Amit", 20, "Delhi", "B.Tech", "Java");

With many parameters, constructors become hard to read and maintain.

Builder Pattern Example

java class Student { private String name; private int age; private String city; private Student(Builder builder) { this.name = builder.name; this.age = builder.age; this.city = builder.city; } static class Builder { private String name; private int age; private String city; Builder setName(String name) { this.name = name; return this; } Builder setAge(int age) { this.age = age; return this; } Builder setCity(String city) { this.city = city; return this; } Student build() { return new Student(this); } } void display() { System.out.println(name + " - " + age + " - " + city); } }

Using Builder

java public class Main { public static void main(String[] args) { Student s = new Student.Builder() .setName("Amit") .setAge(20) .setCity("Delhi") .build(); s.display(); } }

Adapter Pattern

Adapter Pattern is used when two incompatible interfaces need to work together. It acts like a bridge between them.

Real-world example:

  • mobile charger adapter
  • plug converter

Example

Suppose the client expects a Printer interface, but we only have a legacy printer class with a different method name.

java interface Printer { void print(); } class LegacyPrinter { void printDocument() { System.out.println("Printing from legacy printer"); } } class PrinterAdapter implements Printer { private LegacyPrinter legacyPrinter; PrinterAdapter(LegacyPrinter legacyPrinter) { this.legacyPrinter = legacyPrinter; } public void print() { legacyPrinter.printDocument(); } }

The adapter lets incompatible code work together.

Decorator Pattern

Decorator Pattern is used to add new behavior to an object dynamically without changing its original class.

It wraps the original object and extends functionality.

Example Idea

  • simple coffee
  • coffee + milk
  • coffee + milk + sugar

Instead of creating many subclasses, decorators are used.

Observer Pattern

Observer Pattern is used when one object should notify multiple dependent objects automatically when its state changes.

Real-world examples:

  • YouTube subscribers getting notifications
  • stock price updates
  • event listeners in GUI systems

Simple Concept

  • Subject β†’ main object being observed
  • Observer β†’ objects watching the subject

Strategy Pattern

Strategy Pattern is used when multiple algorithms or behaviors are possible, and the behavior should be selected dynamically at runtime.

Example:

  • payment by card
  • payment by UPI
  • payment by wallet

Instead of one big class with many conditions, separate strategy classes are created.

Simple Strategy Pattern Example

java interface PaymentStrategy { void pay(int amount); } class CreditCardPayment implements PaymentStrategy { public void pay(int amount) { System.out.println("Paid by credit card: " + amount); } } class UpiPayment implements PaymentStrategy { public void pay(int amount) { System.out.println("Paid by UPI: " + amount); } } class ShoppingCart { private PaymentStrategy strategy; ShoppingCart(PaymentStrategy strategy) { this.strategy = strategy; } void checkout(int amount) { strategy.pay(amount); } }

This allows behavior to change without modifying the cart class.

How Design Patterns Relate to OOPS

Design patterns are built on top of OOPS fundamentals.

  • Encapsulation β†’ keeps internal details hidden
  • Inheritance β†’ allows extension and reuse
  • Polymorphism β†’ supports flexible design and interchangeable behavior
  • Abstraction β†’ helps reduce direct dependency on concrete classes

That is why understanding OOPS is essential before understanding design patterns deeply.

Benefits of Using Design Patterns

  • better code organization
  • improved maintainability
  • reduced coupling
  • high reusability
  • easier team communication
  • proven solutions to common problems

When Not to Overuse Design Patterns

Although design patterns are powerful, they should not be used unnecessarily. A simple problem does not always need a complex pattern-based solution.

Overusing patterns can make code:

  • harder to understand
  • too abstract
  • over-engineered
Best Practice: Use design patterns where they truly solve a recurring design problem. Do not apply them blindly.

Design Pattern Categories Summary

Category Purpose Examples
Creational Object creation Singleton, Factory, Builder
Structural Class/object composition Adapter, Decorator, Facade
Behavioral Object communication and behavior Observer, Strategy, Command

Real-World Design Pattern Usage in Java

  • Singleton β†’ configuration manager, logger
  • Factory β†’ object creation in frameworks
  • Builder β†’ complex object creation
  • Observer β†’ event listeners, messaging systems
  • Strategy β†’ payment modules, algorithm switching
  • Adapter β†’ integration with old systems

Common Mistakes

  • Trying to memorize pattern names without understanding the problem they solve
  • Using patterns even when simple code would be enough
  • Confusing Factory and Builder patterns
  • Using Singleton carelessly in multithreaded environments
  • Applying inheritance where composition would be better

Best Practices

  • Learn the problem first, then the pattern
  • Prefer simple code unless a pattern clearly improves design
  • Use interfaces and abstraction to reduce coupling
  • Understand real-world examples for each pattern
  • Practice implementing small patterns in Java manually

Interview-Oriented Points

  • Design patterns are reusable solutions to recurring design problems
  • GoF patterns are divided into creational, structural, and behavioral categories
  • Singleton ensures only one object exists
  • Factory hides object creation logic
  • Builder is useful for complex object construction
  • Observer supports one-to-many notification relationships
  • Strategy allows behavior to change dynamically at runtime
  • Patterns improve maintainability, reuse, and communication between developers

Conclusion

Design patterns are an essential part of professional Java programming. They help solve recurring object-oriented design problems in a structured and proven way.

Once you understand the intent behind patterns such as Singleton, Factory, Builder, Adapter, Observer, and Strategy, you start thinking like a software designer rather than only a coder. This makes your Java code more scalable, maintainable, and interview-ready.

Quick Summary: Design patterns are proven object-oriented design solutions that improve flexibility, maintainability, and code reuse, and are commonly grouped into creational, structural, and behavioral categories.

Get Newsletter

Subscibe to our newsletter and we will notify you about the newest updates on Edugators