JavaDesign Patterns Overview

Design Patterns Overview

A design pattern is a reusable, named solution to a problem that recurs across many different programs. Patterns aren’t libraries or code you copy-paste verbatim — they’re a shape of solution, described abstractly enough to apply in many contexts, that developers give a shared name to. When one engineer says “let’s make this a Singleton” or “this smells like it needs a Strategy,” every other engineer who knows the pattern immediately understands the intended structure — design patterns are as much a shared vocabulary as a set of techniques.

Three classic categories

The patterns catalogued in the classic Design Patterns book (the “Gang of Four”) are grouped into three categories, based on what kind of problem they address.

Category

Concerned with

Examples

Creational

How objects get created, hiding the concrete class or construction logic from the caller

Singleton, Builder, Factory Method, Abstract Factory

Structural

How classes and objects are composed into larger structures

Adapter, Decorator, Composite, Facade, Proxy

Behavioral

How objects communicate and distribute responsibility for an algorithm or workflow

Strategy, Observer, Command, Template Method, Iterator

Creational example: Singleton

The Singleton pattern ensures a class has exactly one instance for the entire application, and provides a single, well-known way to access it — useful for things like a shared configuration object or a connection pool where having two independent instances would be a bug, not a feature.

A thread-safe Singleton using an enum

Java
public enum AppConfig {
    INSTANCE;

    private final Map<String, String> settings = new HashMap<>();

    public String get(String key) {
        return settings.get(key);
    }

    public void set(String key, String value) {
        settings.put(key, value);
    }
}

// Usage — always the same instance, everywhere:
AppConfig.INSTANCE.set("env", "production");
String env = AppConfig.INSTANCE.get("env");

An enum with a single constant is a common, safe way to implement Singleton in Java — the JVM guarantees only one instance of an enum constant is ever created, even under concurrent class loading, without needing hand-written synchronization.

Creational example: Builder

The Builder pattern separates the construction of a complex object (one with many optional fields, or where the order of construction matters) from its final representation, using a fluent chain of method calls instead of a constructor with a long, error-prone parameter list.

A fluent Builder for an object with many optional fields

Java
public class Pizza {
    private final String size;
    private final boolean cheese;
    private final boolean pepperoni;

    private Pizza(Builder b) {
        this.size = b.size;
        this.cheese = b.cheese;
        this.pepperoni = b.pepperoni;
    }

    public static class Builder {
        private String size = "medium";
        private boolean cheese = false;
        private boolean pepperoni = false;

        public Builder size(String size) { this.size = size; return this; }
        public Builder cheese(boolean v) { this.cheese = v; return this; }
        public Builder pepperoni(boolean v) { this.pepperoni = v; return this; }

        public Pizza build() { return new Pizza(this); }
    }
}

// Usage — reads like a description of the object being built:
Pizza pizza = new Pizza.Builder()
        .size("large")
        .cheese(true)
        .pepperoni(true)
        .build();

Java’s own standard library uses Builder-like fluent chains widely — StringBuilder, Stream pipelines, and HttpRequest.newBuilder() in the java.net.http package all follow this shape.

Patterns solve specific problems — don't force them
A design pattern earns its complexity when it solves a problem you actually have: genuinely need exactly one instance, genuinely have many optional constructor parameters, genuinely need to swap algorithms at runtime. Reaching for a Singleton, Builder, or Observer just because it’s a well-known name — when a plain class, a constructor, or a simple method would do — adds indirection and ceremony without buying anything. Learn patterns as a vocabulary for recognizing problems, not a checklist to apply everywhere.
  • A design pattern is a named, reusable solution shape for a recurring problem — shared vocabulary, not a library to import.

  • Creational patterns manage object creation; Structural patterns manage composition; Behavioral patterns manage communication and responsibility.

  • Singleton (one instance, globally accessible) and Builder (fluent, step-by-step construction) are two of the most common creational patterns in everyday Java code.

  • Apply a pattern because you recognize its problem in your code — not simply because the pattern is well-known.