Fundamentals 42 min read

Master Design Patterns: Concepts, Real‑World Java Examples, and When to Use Them

This article explains the three major categories of design patterns—creational, structural, and behavioral—provides concise definitions, typical use‑cases, and clear Java code samples for each pattern so developers can write more maintainable and efficient software.

Java Interview Crash Guide
Java Interview Crash Guide
Java Interview Crash Guide
Master Design Patterns: Concepts, Real‑World Java Examples, and When to Use Them

Every technology stack we use is closely related to the ideas of design patterns; mastering these patterns makes our code more standardized, concise, and efficient.

Preface

Design patterns are generally divided into three categories:

Creational patterns: Factory Method, Abstract Factory, Singleton, Builder, Prototype.

Structural patterns: Adapter, Decorator, Proxy, Facade, Bridge, Composite, Flyweight.

Behavioral patterns: Strategy, Template Method, Observer, Iterator, Chain of Responsibility, Command, State, Visitor, Mediator, Interpreter.

Singleton Pattern

Concept

Ensures a class has only one instance, creates it automatically, and provides a global access point.

Typical Scenarios

Generating unique serial numbers.

Shared access points such as a web page counter that should not write to the database on every refresh.

Objects whose creation is resource‑intensive (e.g., I/O or database connections).

Utility classes with many static constants and methods.

Code Example

Thread‑safe version:

public class Singleton {
    private static final Singleton singleton = new Singleton();
    // Prevent external instantiation
    private Singleton() {}
    // Provide global access
    public static Singleton getSingleton() {
        return singleton;
    }
    // Other static methods can be added here
    public static void doSomething() {}
}

Thread‑unsafe version:

public class Singleton {
    private static Singleton singleton = null;
    private Singleton() {}
    public static Singleton getSingleton() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

To make the unsafe version thread‑safe, add the synchronized keyword to getSingleton or synchronize inside the method.

Factory Method Pattern

Concept

Defines an interface for creating objects, letting subclasses decide which class to instantiate. The creation is deferred to subclasses.

Typical Scenarios

JDBC connections, hardware access, reducing object creation and destruction overhead.

Structure

Simple Factory: A single factory class with static methods when only one factory is needed.

Multiple Factories: Each product family has its own creator, adhering to the Single Responsibility Principle.

Replace Singleton: The core requirement of a single instance can also be satisfied by a factory that creates only one object.

Lazy Initialization: The factory caches created objects for reuse.

Code Example

public class ConcreteCreator extends Creator {
    public <T extends Product> T createProduct(Class<T> c) {
        Product product = null;
        try {
            product = (Product) Class.forName(c.getName()).newInstance();
        } catch (Exception e) {
            // handle exception
        }
        return (T) product;
    }
}

Abstract Factory Pattern

Concept

Provides an interface for creating families of related or dependent objects without specifying their concrete classes.

Typical Scenarios

When a set of objects must adhere to the same constraints, such as supporting multiple operating systems.

Code Example

public abstract class AbstractCreator {
    // Create product family A
    public abstract AbstractProductA createProductA();
    // Create product family B
    public abstract AbstractProductB createProductB();
}

Template Method Pattern

Concept

Defines the skeleton of an algorithm in a method, deferring some steps to subclasses so they can redefine specific steps without changing the algorithm's structure.

Typical Scenarios

Multiple subclasses share common logic.

Complex algorithms where the core is fixed but details vary.

Refactoring to extract common code into a parent class.

Structure

Abstract Template: AbstractClass defines two kinds of methods—basic (implemented by subclasses) and the template method (final, non‑overridable).

Code Example

package templateMethod;
public class TemplateMethodPattern {
    public static void main(String[] args) {
        AbstractClass tm = new ConcreteClass();
        tm.templateMethod();
    }
}

// Abstract class
abstract class AbstractClass {
    // Template method (final)
    public final void templateMethod() {
        specificMethod();
        abstractMethod1();
        abstractMethod2();
    }
    public void specificMethod() {
        System.out.println("Concrete method in abstract class called...");
    }
    public abstract void abstractMethod1();
    public abstract void abstractMethod2();
}

// Concrete subclass
class ConcreteClass extends AbstractClass {
    public void abstractMethod1() {
        System.out.println("Implementation of abstract method 1...");
    }
    public void abstractMethod2() {
        System.out.println("Implementation of abstract method 2...");
    }
}

Builder Pattern

Concept

Separates the construction of a complex object from its representation so that the same construction process can create different representations.

Typical Scenarios

When the same construction steps produce different results.

When an object has many parts that can be assembled in various ways.

When the creation process is complex and performance‑critical.

Structure

Product: Often implements the Template Method pattern.

Builder (abstract): Defines how to assemble parts.

ConcreteBuilder: Implements all building steps and returns the finished product.

Director: Controls the order of building steps.

Code Example

public class ConcreteProduct extends Builder {
    private Product product = new Product();
    // Set product parts
    public void setPart() {
        // product part logic
    }
    // Build the product
    public Product buildProduct() {
        return product;
    }
}

Proxy Pattern

Concept

Provides a surrogate or placeholder for another object to control access to it.

Structure

Subject: Abstract role defining common operations.

RealSubject: The actual object that performs the work.

Proxy: Delegates calls to the RealSubject and can add pre‑ or post‑processing.

Code Example

public Object getProxy(ClassLoader classLoader) {
    if (logger.isTraceEnabled()) {
        logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
    }
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

Prototype Pattern

Concept

Specifies the kinds of objects to create using a prototypical instance, and creates new objects by copying this prototype.

Typical Scenarios

Resource‑intensive object initialization.

When creating an object requires complex setup or permissions.

When multiple callers need independent copies of an object.

Advantages

Implements Cloneable and overrides clone() for fast memory‑level copying, avoiding costly constructors.

Code Example

public class PrototypeClass implements Cloneable {
    @Override
    public PrototypeClass clone() {
        PrototypeClass prototype = null;
        try {
            prototype = (PrototypeClass) super.clone();
        } catch (CloneNotSupportedException e) {
            // handle exception
        }
        return prototype;
    }
}

Mediator Pattern

Concept

Encapsulates how a set of objects interact, promoting loose coupling by keeping objects from referring to each other directly.

Typical Scenarios

When many objects are tightly coupled, forming a “spider‑web” of dependencies.

Structure

Mediator (abstract): Defines a unified interface for communication.

ConcreteMediator: Coordinates concrete colleague objects.

Colleague: Each knows the mediator and communicates through it.

Code Example

public abstract class Mediator {
    protected ConcreteColleague1 c1;
    protected ConcreteColleague2 c2;
    public ConcreteColleague1 getC1() { return c1; }
    public void setC1(ConcreteColleague1 c1) { this.c1 = c1; }
    public ConcreteColleague2 getC2() { return c2; }
    public void setC2(ConcreteColleague2 c2) { this.c2 = c2; }
    public abstract void doSomething1();
    public abstract void doSomething2();
}

Command Pattern

Concept

Encapsulates a request as an object, allowing parameterization of clients with different requests, queuing or logging, and supporting undo/redo operations.

Typical Scenarios

GUI button actions, scripting commands, trigger‑feedback mechanisms.

Structure

Receiver: The object that actually performs the action.

Command: Declares an interface for executing an operation.

Invoker: Holds a command and triggers its execution.

Code Example

public class Invoker {
    private Command command;
    public void setCommand(Command command) { this.command = command; }
    public void action() { this.command.execute(); }
}

Chain of Responsibility Pattern

Concept

Gives more than one object a chance to handle a request by forming a chain of handlers.

Responsibilities

1. Define a public handleMessage method.

2. Provide a setNext method to link handlers.

3. Subclasses implement getHandlerLevel and echo for specific processing.

Code Example

public abstract class Handler {
    private Handler nextHandler;
    public final Response handleMessage(Request request) {
        Response response = null;
        if (this.getHandlerLevel().equals(request.getRequestLevel())) {
            response = this.echo(request);
        } else if (this.nextHandler != null) {
            response = this.nextHandler.handleMessage(request);
        }
        return response;
    }
    public void setNext(Handler handler) { this.nextHandler = handler; }
    protected abstract Level getHandlerLevel();
    protected abstract Response echo(Request request);
}

Decorator Pattern

Concept

Dynamically adds responsibilities to an object without affecting other objects of the same class.

Typical Scenarios

Extending a class's functionality.

Adding features that can be removed at runtime.

Modifying a group of sibling classes uniformly.

Structure

Component (abstract): Core interface or abstract class.

ConcreteComponent: The original object to be decorated.

Decorator (abstract): Holds a reference to a Component.

ConcreteDecorator: Adds behavior before/after delegating to the component.

Code Example

@Data
@AllArgsConstructor
@NoArgsConstructor
@Log
class BufferedReader implements Reader {
    private Reader reader;
    @Override
    public void read() { reader.read(); }
    public void readLine() {
        read();
        log.info("Read only one line");
    }
}

Strategy Pattern

Concept

Defines a family of algorithms, encapsulates each one, and makes them interchangeable.

Typical Scenarios

When multiple classes differ only in behavior.

When algorithms need to be swapped at runtime.

When you want to hide algorithmic details from clients.

Structure

Context: Holds a reference to a Strategy.

Strategy (abstract): Declares the algorithm interface.

ConcreteStrategy: Implements the specific algorithm.

Code Example

public enum Calculator {
    ADD("+") {
        public int exec(int a, int b) { return a + b; }
    },
    SUB("-") {
        public int exec(int a, int b) { return a - b; }
    };
    private String value;
    private Calculator(String value) { this.value = value; }
    public String getValue() { return value; }
    public abstract int exec(int a, int b);
}

Adapter Pattern

Concept

Converts the interface of a class into another interface clients expect, allowing incompatible classes to work together.

Typical Scenarios

When you need to adapt an existing class to a new interface, especially during system extensions.

Class Adapter

Target: Desired interface.

Adaptee: Existing class.

Adapter: Inherits from Target and holds an Adaptee instance.

Object Adapter

Uses composition (delegation) instead of inheritance.

Code Example

public class Adapter extends Target {
    private Adaptee adaptee;
    public Adapter(Adaptee adaptee) { this.adaptee = adaptee; }
    @Override
    public void request() { adaptee.specificRequest(); }
}

Iterator Pattern

Concept

Provides a way to access elements of a collection sequentially without exposing its underlying representation.

Structure

Iterator (abstract): Defines hasNext, next, and optionally first.

ConcreteIterator: Implements traversal over a concrete collection.

Aggregate (abstract): Declares a method to create an iterator.

ConcreteAggregate: Implements the collection and iterator creation.

Code Example

public class ConcreteIterator<T> implements Iterator<T> {
    private List<T> list = new ArrayList<>();
    private int cursor = 0;
    public boolean hasNext() { return cursor != list.size(); }
    public T next() {
        T obj = null;
        if (this.hasNext()) {
            obj = this.list.get(cursor++);
        }
        return obj;
    }
}

Composite Pattern

Concept

Composes objects into tree structures to represent part‑whole hierarchies, allowing clients to treat individual objects and compositions uniformly.

Typical Scenarios

Tree‑like structures such as menus or file systems.

When a whole can be broken into independent parts.

Structure

Component (abstract): Declares common operations.

Leaf: Represents end objects.

Composite: Stores child components and implements component operations by delegating to children.

Code Example

public class Composite extends Component {
    private ArrayList<Component> componentArrayList = new ArrayList<>();
    public void add(Component component) { this.componentArrayList.add(component); }
    public void remove(Component component) { this.componentArrayList.remove(component); }
    public ArrayList<Component> getChildren() { return this.componentArrayList; }
}

Observer Pattern

Concept

Defines a one‑to‑many dependency so that when one object changes state, all its dependents are notified and updated automatically.

Typical Scenarios

Event‑driven systems, message queues, UI updates.

Structure

Subject: Manages observers and notifies them.

Observer: Defines an update method.

Code Example

public abstract class Subject {
    private Vector<Observer> obsVector = new Vector<>();
    public void addObserver(Observer o) { this.obsVector.add(o); }
    public void delObserver(Observer o) { this.obsVector.remove(o); }
    public void notifyObservers() { for (Observer o : this.obsVector) { o.update(); } }
}

Facade Pattern

Concept

Provides a unified high‑level interface to a set of subsystems, making them easier to use.

Typical Scenarios

Simplifying complex modules for external clients.

Encapsulating subsystem interactions.

Structure

Facade: Delegates client requests to appropriate subsystem objects.

Subsystems: Individual components that perform the real work.

Code Example

public class Client {
    private A a = new A();
    private B b = new B();
    private C c = new C();
    public void methodA() { a.doSomething(); }
    public void methodB() { b.doSomething(); }
    public void methodC() { c.doSomething(); }
}

Memento Pattern

Concept

Captures an object's internal state without violating encapsulation, allowing the object to be restored later.

Typical Scenarios

Undo/redo operations.

Transactional state management.

Structure

Originator: Creates and restores Mementos.

Memento: Stores the internal state.

Caretaker: Manages saved Mementos.

Code Example

public class BeanUtils {
    // Backup all bean properties into a map
    public static HashMap<String, Object> backupProp(Object bean) {
        HashMap<String, Object> result = new HashMap<>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor des : descriptors) {
                String fieldName = des.getName();
                Method getter = des.getReadMethod();
                Object fieldValue = getter.invoke(bean);
                if (!fieldName.equalsIgnoreCase("class")) {
                    result.put(fieldName, fieldValue);
                }
            }
        } catch (Exception e) {
            // handle exception
        }
        return result;
    }
    // Restore properties from a map back to the bean
    public static void restoreProp(Object bean, HashMap<String, Object> propMap) {
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor des : descriptors) {
                String fieldName = des.getName();
                if (propMap.containsKey(fieldName)) {
                    Method setter = des.getWriteMethod();
                    setter.invoke(bean, propMap.get(fieldName));
                }
            }
        } catch (Exception e) {
            System.out.println("error");
            e.printStackTrace();
        }
    }
}

Visitor Pattern

Concept

Encapsulates operations to be performed on elements of an object structure without changing the classes of the elements.

Typical Scenarios

When many unrelated operations need to be performed on a set of objects.

Avoid polluting element classes with many unrelated methods.

Structure

Visitor (abstract): Declares visit methods for each concrete element.

ConcreteVisitor: Implements the operations.

Element (abstract): Declares an accept method.

ConcreteElement: Calls visitor.visit(this).

Code Example

public class CompensationVisitor implements Visitor {
    @Override
    public void visit(Element element) {
        Employee employee = (Employee) element;
        System.out.println(employee.getName() + "'s Compensation is " +
            (employee.getDegree() * employee.getVacationDays() * 10));
    }
}

State Pattern

Concept

Allows an object to alter its behavior when its internal state changes, appearing as if the object changed its class.

Typical Scenarios

When behavior depends on state (e.g., user permissions).

Replacing complex conditional logic.

Structure

State (abstract): Defines interface for state-specific behavior and holds a reference to the context.

ConcreteState: Implements behavior for a particular state and may transition to other states.

Context: Maintains a reference to a State object and delegates state‑dependent behavior.

Code Example

public abstract class State {
    protected Context context;
    public void setContext(Context _context) { this.context = _context; }
    public abstract void handle1();
    public abstract void handle2();
}

Interpreter Pattern

Concept

Given a language, defines a representation for its grammar and an interpreter that uses the representation to interpret sentences in the language.

Typical Scenarios

Repeatedly occurring problems that can be expressed as a language.

Simple grammar parsing.

Structure

AbstractExpression: Declares an interpret method.

TerminalExpression: Implements interpretation of terminal symbols.

NonterminalExpression: Implements interpretation of non‑terminal symbols.

Context: Stores information needed during interpretation (often a map).

Code Example

public class TerminalExpression extends AbstractExpression {
    @Override
    public void interpret(Context ctx) {
        // implementation for terminal symbols
    }
}

public class NonterminalExpression extends AbstractExpression {
    @Override
    public void interpret(Context ctx) {
        // implementation for non‑terminal symbols
    }
}

Flyweight Pattern

Concept

Uses sharing to support large numbers of fine‑grained objects efficiently by separating intrinsic (shared) and extrinsic (context‑dependent) state.

Typical Scenarios

Systems with many similar objects.

When objects have identical intrinsic state and varying extrinsic state.

Object pooling requirements.

Structure

Flyweight (abstract): Defines methods for intrinsic and extrinsic state.

ConcreteFlyweight: Implements intrinsic state.

UnsharedConcreteFlyweight: Objects that cannot be shared.

FlyweightFactory: Creates and manages flyweight objects.

Code Example

public class FlyweightFactory {
    private static HashMap<String, Flyweight> pool = new HashMap<>();
    public static Flyweight getFlyweight(String key) {
        Flyweight flyweight = null;
        if (pool.containsKey(key)) {
            flyweight = pool.get(key);
        } else {
            flyweight = new ConcreteFlyweight1(key);
            pool.put(key, flyweight);
        }
        return flyweight;
    }
}

Bridge Pattern

Concept

Decouples an abstraction from its implementation so that the two can vary independently.

Typical Scenarios

When inheritance is not suitable.

Unstable abstraction or implementation interfaces.

High reuse requirements.

Structure

Abstraction: Holds a reference to an Implementor and defines high‑level operations.

Implementor (interface): Declares low‑level operations.

RefinedAbstraction: Extends Abstraction with additional behavior.

ConcreteImplementor: Implements the Implementor interface.

Code Example

public abstract class Abstraction {
    private Implementor imp;
    public Abstraction(Implementor _imp) { this.imp = _imp; }
    public void request() { this.imp.doSomething(); }
    public Implementor getImp() { return imp; }
}

Conclusion

When learning design patterns, don’t view them as overly difficult; they are essentially high‑level abstractions. Understanding the underlying principles and when to apply each pattern helps solve real‑world development problems more effectively.

Design patterns are not rigid formulas to memorize; the key is grasping their abstract ideas and how they can improve code quality, maintainability, and flexibility.

- END -

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Design Patternssoftware architecturebehavioral-patternscreational patternsStructural Patternsjava examples
Java Interview Crash Guide
Written by

Java Interview Crash Guide

Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.