โ 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