// Design Patterns · 22
Template Method
Fix the steps of an algorithm, let subclasses fill some in.
How it fits together
- ImportJob uses / calls ImporterBase (Import())
- CsvImporter extends ImporterBase
- XmlImporter extends ImporterBase
Spot it
- Copy-pasted classes that differ in one step
- Every importer reads, validates, then saves
- Subclasses forget to call base.Process()
It costs
Ties variation to inheritance; deep hierarchies get rigid and hard to test.
In code
public abstract class ImporterBase(IRowStore store){ public int Import(Stream input) { var valid = Parse(input) .Where(IsValid) .ToList(); store.Save(valid); OnImported(valid.Count); return valid.Count; } protected abstract IReadOnlyList<ImportRow> Parse(Stream input); protected virtual void OnImported(int count) { } private static bool IsValid(ImportRow row) => !string.IsNullOrWhiteSpace(row.Sku);}Go deeperThe full explanation and what to ask for · 1 min readExpandCollapse
The base class owns the algorithm and calls out to abstract steps and optional hooks that subclasses supply. The base calls the subclass, not the other way round.
Too many hooks, or a template method that subclasses can override, and the fixed order is no longer fixed. When the varying step is independent of the rest, pass it in as a strategy instead of inheriting.
Frameworks use this shape for long-running workers and authentication handlers: the base class handles start, stop or the request flow, and the subclass fills in one overridable step.
Ask for it
- template method
- abstract step
- hook method
- base class
- inversion of control
CsvImporter and XmlImporter duplicate the read-validate-save flow. Extract an abstract ImporterBase with an Import() method that subclasses cannot override. It calls an abstract Parse() step and an optional OnImported() hook, then make both importers derive from it.