In this lesson, you will learn how to define a fixed algorithmic skeleton in a trait while allowing specific steps to be customized by implementers using the Template Method pattern.
The Core Concept
The Template Method pattern is about structure. Imagine you have a process, like generating a report, that always follows the same steps: Fetch Data, Process Data, and Format Output. While the order of these steps never changes, the implementation of each step might vary depending on the data source.
In Rust, we achieve this by defining a trait that contains a "template" method—a concrete method that orchestrates the workflow—alongside abstract "hook" methods that implementers must define.
Implementing the Workflow
Unlike languages with class inheritance, we define our template method directly inside the trait using a default implementation.
trait ReportGenerator {
// The Template Method: The fixed algorithm
fn generate_report(&self) {
let data = self.fetch_data();
let processed = self.process_data(data);
println!("Final Report: {}", self.format_output(processed));
}
// The Hooks: Steps left to implementers
fn fetch_data(&self) -> String;
fn process_data(&self, data: String) -> String;
fn format_output(&self, data: String) -> String;
}
By providing generate_report as a default method, you ensure that every type implementing ReportGenerator follows your exact sequence of operations. The implementer doesn't need to worry about the orchestration logic; they only need to fill in the "hooks" (fetch_data, process_data, and format_output).
Why This Matters
This pattern enforces consistency across your architecture. By baking the workflow into the trait, you prevent "logic leakage," where different parts of your codebase might accidentally execute steps in the wrong order or skip a crucial validation step. It acts as a contract for how a process should run, leaving the what to the individual types.
Key Takeaway: The Template Method pattern uses trait default methods to define a fixed algorithmic workflow, forcing implementers to provide specific logic only for the individual steps defined as hooks.