โ† Back to Design Patterns
๐Ÿ“‹
Behavioral

Template Method

Defines the skeleton of an algorithm in a base class, deferring specific steps to subclasses.

The Problem

Multiple classes implement similar algorithms with the same structure but different steps. Duplicated scaffolding code exists in every class.

How It Works

  • โ€บBase class defines the algorithm's skeleton โ€” the overall sequence of steps
  • โ€บSubclasses override specific steps without changing the overall structure
  • โ€บfinal on the template method prevents subclasses from altering the sequence
  • โ€บHook methods are optional overrides that provide extension points
  • โ€บHollywood Principle: 'Don't call us, we'll call you' โ€” the base class drives

When to Use

โœ“Multiple classes share the same algorithm structure with only some steps differing
โœ“Framework code that calls user-defined steps at specific points
โœ“Eliminating code duplication across similar classes
โœ“Data processing pipelines: fetch โ†’ parse โ†’ format โ†’ store

Real-World Examples

๐ŸŽ
iOS

UIViewController lifecycle (viewDidLoad, viewWillAppear, viewDidAppear), UIView draw(_:)

๐Ÿค–
Android

Fragment lifecycle (onCreate, onCreateView, onResume), Activity onCreate flow

๐ŸŒ
Web

React component lifecycle, Express route handler flow, Jest test lifecycle (beforeEach / afterEach)

Code Examples

Swift
class ReportGenerator {
    // Template method โ€” final so subclasses can't change the sequence
    final func generate() -> String {
        let data    = fetchData()
        let parsed  = parseData(data)
        let report  = formatReport(parsed)
        return report
    }

    func fetchData() -> String { "raw:server" }
    func parseData(_ raw: String) -> [String] { [raw] }
    func formatReport(_ items: [String]) -> String { items.joined(separator: "\n") }
}

class JSONReport: ReportGenerator {
    override func parseData(_ raw: String) -> [String] { ["JSON:\(raw)"] }
    override func formatReport(_ items: [String]) -> String {
        "{\(items.joined(separator: ","))}"
    }
}

class CSVReport: ReportGenerator {
    override func formatReport(_ items: [String]) -> String {
        items.joined(separator: ",")
    }
}

print(JSONReport().generate())  // {JSON:raw:server}
print(CSVReport().generate())   // raw:server