Design Patterns in Java: Key Examples and Implementations

Behavioral Patterns

Strategy Pattern

Defines a family of algorithms, encapsulates each, and makes them interchangeable. Context uses a Strategy object to vary its behavior.

Roles:

  • Strategy: Interface declaring algorithm methods
  • ConcreteStrategy: Implements specific algorithm
  • Context: Maintains strategy reference

Example: E-comerce Discounts

interface PricingStrategy {
    double calculatePrice(double price, int quantity);
}

class StandardPricing implements PricingStrategy {
    @Override
    public double calculatePrice(double price, int quantity) {
        return price * quantity;
    }
}

class PremiumDiscount implements PricingStrategy {
    @Override
    public double calculatePrice(double price, int quantity) {
        return price * quantity * 0.8;
    }
}

class OrderProcessor {
    private PricingStrategy strategy;
    
    public OrderProcessor(PricingStrategy strategy) {
        this.strategy = strategy;
    }
    
    public double processOrder(double price, int quantity) {
        return strategy.calculatePrice(price, quantity);
    }
}

Command Pattern

Encapsulates a request as an object, allowing parameterization and queuing of requests.

Roles:

  • Command: Interface for execution
  • ConcreteCommand: Binds action to receiver
  • Invoker: Triggers command execution
  • Receiver: Performs actual operations

Example: Restaurent Order System

interface KitchenCommand {
    void execute();
    void undo();
}

class CookReceiver {
    public void prepareDish() {
        System.out.println("Cooking dish...");
    }
    
    public void cancelPreparation() {
        System.out.println("Canceling order...");
    }
}

class OrderCommand implements KitchenCommand {
    private CookReceiver chef;
    
    public OrderCommand(CookReceiver chef) {
        this.chef = chef;
    }
    
    @Override
    public void execute() {
        chef.prepareDish();
    }
    
    @Override
    public void undo() {
        chef.cancelPreparation();
    }
}

class WaiterInvoker {
    private KitchenCommand command;
    
    public void setCommand(KitchenCommand command) {
        this.command = command;
    }
    
    public void submitOrder() {
        command.execute();
    }
}

Template Method Pattern

Defines algorithm skeleton in superclass, allowing subclasses to override specific steps.

Example: Food Delivery

abstract class FoodOrder {
    public final void processOrder() {
        selectItems();
        processPayment();
        deliverItems();
        optionalTip();
    }
    
    abstract void selectItems();
    
    void processPayment() {
        System.out.println("Processing payment...");
    }
    
    void deliverItems() {
        System.out.println("Delivery in progress...");
    }
    
    void optionalTip() {}
}

class CoffeeOrder extends FoodOrder {
    @Override
    void selectItems() {
        System.out.println("Selecting coffee items");
    }
    
    @Override
    void optionalTip() {
        System.out.println("Adding tip for delivery");
    }
}

Observer Pattern

Defines one-to-many dependency betwean objects. When one changes state, dependents are notified.

Example: State Monitoring

import java.util.*;

interface StateObserver {
    void update(int state);
}

class StateSubject {
    private List<StateObserver> observers = new ArrayList<>();
    private int currentState;
    
    public void attach(StateObserver observer) {
        observers.add(observer);
    }
    
    public void setState(int state) {
        currentState = state;
        notifyObservers();
    }
    
    private void notifyObservers() {
        for (StateObserver o : observers) {
            o.update(currentState);
        }
    }
}

class Display implements StateObserver {
    @Override
    public void update(int state) {
        System.out.println("State changed to: " + state);
    }
}

Iterator Pattern

Provides sequential access to elements of aggregate objects.

Example: Student Collection

interface StudentIterator {
    boolean hasNext();
    Student next();
}

class ClassIterator implements StudentIterator {
    private List<Student> students;
    private int position;
    
    public ClassIterator(List<Student> list) {
        students = list;
    }
    
    @Override
    public boolean hasNext() {
        return position < students.size();
    }
    
    @Override
    public Student next() {
        return students.get(position++);
    }
}

class StudentCollection {
    private List<Student> students = new ArrayList<>();
    
    public StudentIterator iterator() {
        return new ClassIterator(students);
    }
    
    public void addStudent(Student s) {
        students.add(s);
    }
}

Creational Patterns

Singleton Pattern

Ensures single instance existence.

Implementation:

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

Factory Method Pattern

Delegates object creation to subclasses.

Example: Shape Factory

interface Shape {
    void draw();
}

class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing circle");
    }
}

class ShapeFactory {
    public Shape createShape(String type) {
        if ("circle".equalsIgnoreCase(type)) {
            return new Circle();
        }
        return null;
    }
}

Builder Pattern

Constructs complex objects step-by-step.

Example: Meal Composer

class Meal {
    private String mainCourse;
    private String side;
    private String drink;
    
    // Setters omitted for brevity
}

interface MealBuilder {
    void buildMain();
    void buildSide();
    void buildDrink();
    Meal getMeal();
}

class VegMealBuilder implements MealBuilder {
    private Meal meal = new Meal();
    
    @Override
    public void buildMain() {
        meal.setMainCourse("Veg Burger");
    }
    
    // Other implementations omitted
}

class MealDirector {
    public Meal createMeal(MealBuilder builder) {
        builder.buildMain();
        builder.buildSide();
        builder.buildDrink();
        return builder.getMeal();
    }
}

Prototype Pattern

Creates objects by cloning prototypes.

Example: Skill Replication

abstract class Ability implements Cloneable {
    public abstract Ability cloneAbility();
}

class Fireball extends Ability {
    @Override
    public Fireball cloneAbility() {
        return new Fireball();
    }
}

class AbilityManager {
    private Ability prototype;
    
    public AbilityManager(Ability prototype) {
        this.prototype = prototype;
    }
    
    public Ability createAbility() {
        return prototype.cloneAbility();
    }
}

Structural Patterns

Adapter Pattern

Bridges incompatible interfaces.

Example: Translation Service

interface LocalizationService {
    void translate(String text, String targetLanguage);
}

class TranslatorAdaptee {
    public void translateText(String text, String lang) {
        System.out.println("Translating: " + text + " to " + lang);
    }
}

class TranslatorAdapter implements LocalizationService {
    private TranslatorAdaptee adaptee = new TranslatorAdaptee();
    
    @Override
    public void translate(String text, String target) {
        adaptee.translateText(text, target);
    }
}

Decorator Pattern

Dynamically adds responsibilities.

Example: Game Character Enhancements

interface Character {
    void displaySkills();
}

class Warrior implements Character {
    @Override
    public void displaySkills() {
        System.out.println("Basic warrior skills");
    }
}

abstract class SkillDecorator implements Character {
    protected Character decoratedCharacter;
    
    public SkillDecorator(Character character) {
        decoratedCharacter = character;
    }
}

class FireEnchantment extends SkillDecorator {
    public FireEnchantment(Character character) {
        super(character);
    }
    
    @Override
    public void displaySkills() {
        decoratedCharacter.displaySkills();
        System.out.println("Added fire damage");
    }
}

Proxy Pattern

Controls access to another object.

Dynamic Proxy Example:

import java.lang.reflect.*;

interface NetworkAccess {
    void connect(String url);
}

class RealInternet implements NetworkAccess {
    @Override
    public void connect(String url) {
        System.out.println("Connecting to " + url);
    }
}

class AccessHandler implements InvocationHandler {
    private Object target;
    
    public AccessHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Access control check");
        return method.invoke(target, args);
    }
}

class DynamicProxyDemo {
    public static void main(String[] args) {
        NetworkAccess real = new RealInternet();
        NetworkAccess proxy = (NetworkAccess) Proxy.newProxyInstance(
            real.getClass().getClassLoader(),
            new Class[]{NetworkAccess.class},
            new AccessHandler(real)
        );
        proxy.connect("example.com");
    }
}

Facade Pattern

Simplifies complex subsystem interfaces.

Example: Travel Booking

class FlightBooker {
    public void bookFlight() { /* Implementation */ }
}

class HotelBooker {
    public void bookRoom() { /* Implementation */ }
}

class TravelFacade {
    private FlightBooker flightBooker;
    private HotelBooker hotelBooker;
    
    public TravelFacade() {
        flightBooker = new FlightBooker();
        hotelBooker = new HotelBooker();
    }
    
    public void arrangeTrip() {
        flightBooker.bookFlight();
        hotelBooker.bookRoom();
    }
}

Bridge Pattern

Decouples abstraction from implementation.

Example: Device Controllers

interface DeviceController {
    void operate();
}

class RemoteControl {
    protected DeviceController controller;
    
    public RemoteControl(DeviceController controller) {
        this.controller = controller;
    }
    
    public void execute() {
        controller.operate();
    }
}

class TVController implements DeviceController {
    @Override
    public void operate() {
        System.out.println("TV operation");
    }
}

Tags: java Design Patterns Software Architecture Object-Oriented Design programming

Posted on Wed, 15 Jul 2026 17:25:21 +0000 by seaweed