Design Pattern

Template Method Pattern

Clean Java-only production-ready implementation.


You have an algorithm with a fixed sequence of steps, but some steps vary across implementations. Template Method puts the invariant skeleton in the base class and allows subclasses to override specific steps.

// ─── EXAMPLE 1 ──────────────────────────────────────────────────────────────
// WHAT WE ARE IMPLEMENTING:
// A continuous software delivery compiler specifying strict testing,
// building, and deployment pipelines.
//
// WHERE THE TEMPLATE METHOD FITS IN:
// BuildPipeline is the Abstract Class defining the template method
// runPipeline(). JavaBuildPipeline represents a Concrete Class customizing
// compiling.
// ────────────────────────────────────────────────────────────────────────────
abstract class DataProcessor {
    // Template method — defines the skeleton
    public final void process(String data) {
        System.out.println("\n=== Processing " + getProcessorName() + " ===");
        String parsed = parse(data);
        boolean valid = validate(parsed);
        if (!valid) {
            System.out.println("  Validation failed — aborting");
            onError(data);
            return;
        }
        save(parsed);
        notifyComplete(parsed);
    }

    // Steps subclasses must implement
    protected abstract String getProcessorName();
    protected abstract String parse(String data);
    protected abstract boolean validate(String data);
    protected abstract void save(String data);

    // Hook — optional override
    protected void onError(String data) {
        System.out.println("  [Default] Logged error");
    }

    // Hook — optional override
    protected void notifyComplete(String data) {
        System.out.println("  [Default] Notification sent");
    }
}

class CsvProcessor extends DataProcessor {
    protected String getProcessorName() { return "CSV"; }
    protected String parse(String data) { return data.replace(",", " | "); }
    protected boolean validate(String data) { return data != null && !data.isEmpty(); }
    protected void save(String data) { System.out.println("  [CSV] Saved: " + data); }
}

class JsonProcessor extends DataProcessor {
    protected String getProcessorName() { return "JSON"; }
    protected String parse(String data) { return "[Parsed JSON]: " + data; }
    protected boolean validate(String data) { return data != null && data.startsWith("{"); }
    protected void save(String data) { System.out.println("  [JSON] Stored: " + data); }
    protected void notifyComplete(String data) { System.out.println("  [JSON] Published to event bus"); }
}

public class Main {
    public static void main(String[] args) {
        DataProcessor csv = new CsvProcessor();
        csv.process("a,b,c");

        DataProcessor json = new JsonProcessor();
        json.process("{\"key\": \"value\"}");
        json.process("invalid");  // Validation fails
    }
}