SwadhyAI Notes

All Low-Level Design notes

Behavioral · Gang of Four

Template Method

Template Method is a behavioral pattern that fixes the outline of an algorithm in a base class and lets subclasses fill in the varying steps. The shared sequence lives in one place.

Example: every import job parses a file, validates rows, then persists. CSV and JSON differ in parse; vendors differ in validate. If you copy the outline into two classes, adding “audit log after persist” means editing both. Put the outline in the base class once instead.

Recipe

Shared outline, hollow steps

The base method is usually so nobody rearranges the outline. The are abstract or have do-nothing defaults. That is inheritance used for a stable sequence, not for a taxonomy of the real world. See composition vs inheritance.

  1. base · final

    run(Path file)

    calls the three steps in this order. Hollywood: we call you.

  2. 1

    parse(file)

    abstract

    CsvImport / JsonImport

  3. 2

    validate(rows)

    abstract

    VendorA / VendorB

  4. 3

    persist(rows)

    shared

    ImportJob default

Strategy is the composition twin

If the whole policy changes — pricing, allocation — inject a strategy. If the steps stay in order and two of them change, a template is honest. Interviewers often prefer Strategy because you can test the context with a fake and you avoid a deep base class.

Chain is a different shape

A chain of handlers can stop the walk. A template usually runs every step. Factory Method is often a hook inside a template (“which parser?”). The principle is the same sentence.

Java: share the steps, vary the hooks

Keep the base small. That is also OCP: a new vendor is a new subclass, not a new if in run().

java
abstract class ImportJob {
  final void run(Path file) {
    List<Row> rows = parse(file);
    validate(rows);
    persist(rows);
  }

  abstract List<Row> parse(Path file);
  abstract void validate(List<Row> rows);

  void persist(List<Row> rows) {
    rows.forEach(repository::save);
  }
}

class CsvImport extends ImportJob {
  List<Row> parse(Path file) { /* split commas */ return List.of(); }
  void validate(List<Row> rows) { /* required columns */ }
}

class JsonImport extends ImportJob {
  List<Row> parse(Path file) { /* read array */ return List.of(); }
  void validate(List<Row> rows) { /* schema */ }
}

How to implement it (steps)

1

Write the outline once

parse → validate → persist. Mark run() final.

2

Make the varying steps hooks

abstract parse, abstract validate, default persist if shared.

3

Do not let subclasses reorder

A different outline needs a different template or a Strategy.

A base class that is really a God object

If ImportJob also sends email, opens JDBC, and formats CSV, subclasses inherit a swamp. The template should be the sequence, not the application.

Using inheritance when you meant Strategy

CsvImport versus JsonImport is a template if the outline is shared. Hourly versus airport pricing is not a subclass of ParkingLot. That variation is a strategy you pass in.

Strategy vs Template, side by side

Same variation, two shapes. Prefer Strategy when you want a fake in tests and no base class. Prefer Template when copying the outline would be the bug and the sequence is the product.

LensTemplate MethodStrategy
What is fixed?The order of stepsThe context’s job; the algorithm swaps
How you varySubclass hooksInject an object
Test seamSubclass or extract hooksPass a fake strategy
Interview defaultImport jobs, report pipelinesPricing, allocation, win rules

Java: a hook that is a factory method

“Which parser?” can be a factory method inside the template. The outline still owns run().

java
abstract class ImportJob {
  final void run(Path file) {
    Parser parser = parser();
    List<Row> rows = parser.parse(file);
    validate(rows);
    persist(rows);
  }

  abstract Parser parser();
  abstract void validate(List<Row> rows);
}

Empty overrides are a smell

If JsonImport no-ops validate and persist, you forced the wrong skeleton. Split templates or use Strategy for the steps that actually move.

Keep the base small

JDBC, email, and CSV formatting do not belong on ImportJob. Inject a repository. The template is the sequence.

How to explain this in an interview

“The outline is shared; parse and validate vary. run() is final.” If they then change pricing on a lot, do not subclass ParkingLot — inject a strategy. Empty overrides mean you picked the wrong skeleton. JDBC and email do not belong on ImportJob.

Hollywood: the base calls the hooks. A factory method inside the template is a legal hook, not a second outline.

Nearby in LLD