Template Method
Template Method fixes the order of a multi-step algorithm in a base class and lets subclasses override variable steps.
Introduction
Template Method fixes the order of a multi-step algorithm in a base class and lets subclasses override variable steps. The Hollywood Principle — don't call us, we'll call you. Framework hooks: HttpServlet.service() calls doGet/doPost; JUnit setUp/test/tearDown; every "override hook X" in a base class is Template Method.
The story
A nightly ETL had CSV, JSON, XML importers each with 500-line open-parse-validate-transform-load-audit methods. Extracting common ETL into a base class with overrideable parse() and transform() hooks made Parquet importer 80 lines inheriting validation/audit/load.
The business problem
Duplicated multi-step algorithms diverge when steps are copy-pasted:
- Structural drift: one importer forgets validation or audit step.
- Boilerplate duplication: same skeleton in every variant class.
- New variant cost: reimplement entire flow for one different step.
- Inconsistent ordering: steps run in wrong order in one variant.
The problem teams faced
Template Method fits when:
- Several classes implement same multi-step algorithm with minor step differences.
- Algorithm structure must stay fixed; only some steps vary.
- Framework defines lifecycle; users fill hooks.
- Shared steps (audit, metrics) must never be skipped.
Understanding the topic
Intent: Define algorithm skeleton in base method; subclasses override primitive steps.
- AbstractClass — templateMethod() final; calls abstract hooks.
- ConcreteClass — overrides primitiveStepA/B; optional hookC.
- Hollywood Principle — base calls subclass hooks, not reverse.
Internal architecture
ETL template method:
abstract class EtlImporter {import(source: string): Report {const raw = this.open(source)const parsed = this.parse(raw) // abstractconst valid = this.validate(parsed) // sharedconst transformed = this.transform(valid) // abstractthis.load(transformed) // sharedthis.audit(source) // shared — can't skipreturn this.buildReport()}protected abstract parse(raw: Buffer): Row[]protected abstract transform(rows: Row[]): Row[]}
Visual explanation
Three diagrams cover template flow, hooks, and vs Strategy:
Informative example
Before / after — duplicated ETL to template:
// ❌ Each importer duplicates validate/load/auditclass CsvImporter {import(path: string) {const raw = fs.readFileSync(path)const rows = parseCsv(raw)validate(rows); load(rows); audit(path) // duplicated}}// ✅ Template Method — shared skeleton, override parse onlyabstract class EtlImporter {import(path: string) {const raw = this.open(path)const rows = this.parse(raw)this.validate(rows); this.load(rows); this.audit(path)}protected abstract parse(raw: Buffer): Row[]}class CsvImporter extends EtlImporter {protected parse(raw: Buffer) { return parseCsv(raw) }}
Execution workflow
Identify skeleton
Steps that never change order.
Real-world use
HttpServlet, JUnit test lifecycle, Spring JdbcTemplate callbacks, Android Activity lifecycle, build tool task bases, game loop update/render hooks.
Production case study
Multi-format ETL importers:
- Scenario: CSV, JSON, XML importers each 500 lines with duplicated validate/audit.
- Decision: EtlImporter base with abstract parse/transform.
- Outcome: Parquet importer 80 lines; inherited validation and audit.
Trade-offs
- Pro: invariant structure enforced; shared steps never skipped.
- Pro: new variant overrides only differing steps.
- Con: inheritance coupling — fragile base class.
- Con: awkward in languages/compositions preferring composition.
Decision framework
- Use when algorithm structure fixed and only some steps vary.
- Use in frameworks defining lifecycle for extension.
- Avoid when whole algorithm varies — Strategy instead.
- Avoid deep inheritance in TS/React — hooks/composition often better.
Best practices
- Keep templateMethod short and readable — delegate to named private steps.
- Document which hooks are required vs optional.
- Prefer composition + Strategy in modern TS when inheritance awkward.
Anti-patterns to avoid
- Template method with 20 abstract methods — too many extension points.
- Subclass overriding templateMethod — breaks invariant structure.
- Template Method when Strategy + composition clearer.
Common mistakes
- Fragile base class — change to shared step breaks all subclasses.
- Leaking subclass types through template base API.
Debugging tips
- Log each step name in templateMethod — trace which hook fails.
- Test shared steps once in base class tests.
Optimization strategies
- Lazy steps via hooks — skip expensive hook when not needed.
Common misconceptions
- Template Method is main inheritance use case in GoF — one of few justified extends.
- React lifecycle was Template Method — now hooks replace inheritance form.
- Strategy varies whole algorithm; Template varies steps within fixed skeleton.
Advanced interview questions
Interview Prep
Practice concise answers, then expand each card for the explanation.
1IntermediateQuestionTemplate Method vs Strategy?+
Answer
Follow-up
2AdvancedQuestionWhat is Hollywood Principle?+
Answer
Follow-up
3BeginnerQuestionHook vs abstract method?+
Answer
Follow-up
4AdvancedQuestionTemplate Method in modern TS?+
Answer
Follow-up
Summary
You can extract ETL-style skeletons with Template Method and distinguish from Strategy. Tell the Parquet 80-line importer story — if you can do that, you own Template Method.