Factory and Strategy Patterns

OOP · lesson 15 of 43 · 4 min read

How to pass behaviour in as a parameter and centralise the decision of which implementation to build.

Open this lesson in the learning hub

Key points

  • Strategy: pass the algorithm in as an object. The caller picks the behaviour; the surrounding class never changes.
  • In modern Java a strategy is usually just a lambda against a functional interface. No class explosion required.
  • Comparator, Predicate and Function are strategies the JDK already ships for you.
  • Factory: one place decides which implementation to create, so callers only ever depend on the interface.
  • Static factory methods beat new for naming, caching and returning subtypes. See List.of and Optional.of.
  • A registry Map from key to supplier turns an ever-growing switch into data you can extend.

Example

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

public class Main {
    // STRATEGY: the algorithm is just another parameter.
    interface Discount { double apply(double amount); }

    static double checkout(double amount, Discount discount) {
        return discount.apply(amount);
    }

    // FACTORY: one place decides which implementation the caller gets.
    interface Notifier { String send(String msg); }

    static final Map<String, Supplier<Notifier>> REGISTRY = Map.of(
        "email", () -> msg -> "email -> " + msg,
        "sms",   () -> msg -> "sms   -> " + msg
    );

    static Notifier notifierFor(String channel) {
        Supplier<Notifier> factory = REGISTRY.get(channel);
        if (factory == null) throw new IllegalArgumentException("unknown channel: " + channel);
        return factory.get();
    }

    public static void main(String[] args) {
        System.out.println(checkout(100, amount -> amount));         // no discount
        System.out.println(checkout(100, amount -> amount * 0.9));   // 10% off
        System.out.println(checkout(100, amount -> amount - 15));    // flat 15

        System.out.println(notifierFor("email").send("build is green"));
        System.out.println(notifierFor("sms").send("build is green"));

        // Comparator is the JDK's own Strategy interface.
        List<String> names = new ArrayList<>(List.of("Bea", "Al", "Cyd"));
        names.sort(Comparator.comparingInt(String::length));
        System.out.println(names);
    }
}

Strategy swaps the how; factory hides the which.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the OOP course, and every lesson in it is listed on the OOP contents page.