What Problem It Solves
You have an algorithm with a fixed sequence of steps, but some steps vary across implementations. Template Method puts the invariant skeleton in the base class and allows subclasses to override specific steps.
Template Method vs Strategy
| Aspect | Template Method | Strategy |
|---|---|---|
| Scope | Algorithm skeleton with fixed steps | Entire algorithm interchangeable |
| Control | Base class controls the sequence | Context delegates entire algorithm |
| Variation | Override specific steps | Replace entire algorithm |
| Inheritance | Yes (subclass overrides) | No (composition) |
Implementation
// โโโ EXAMPLE 1 โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// WHAT WE ARE IMPLEMENTING:
// A continuous software delivery compiler specifying strict testing,
// building, and deployment pipelines.
//
// WHERE THE TEMPLATE METHOD FITS IN:
// BuildPipeline is the Abstract Class defining the template method
// runPipeline(). JavaBuildPipeline represents a Concrete Class customizing
// compiling.
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
abstract class DataProcessor {
// Template method โ defines the skeleton
public final void process(String data) {
System.out.println("\n=== Processing " + getProcessorName() + " ===");
String parsed = parse(data);
boolean valid = validate(parsed);
if (!valid) {
System.out.println(" Validation failed โ aborting");
onError(data);
return;
}
save(parsed);
notifyComplete(parsed);
}
// Steps subclasses must implement
protected abstract String getProcessorName();
protected abstract String parse(String data);
protected abstract boolean validate(String data);
protected abstract void save(String data);
// Hook โ optional override
protected void onError(String data) {
System.out.println(" [Default] Logged error");
}
// Hook โ optional override
protected void notifyComplete(String data) {
System.out.println(" [Default] Notification sent");
}
}
class CsvProcessor extends DataProcessor {
protected String getProcessorName() { return "CSV"; }
protected String parse(String data) { return data.replace(",", " | "); }
protected boolean validate(String data) { return data != null && !data.isEmpty(); }
protected void save(String data) { System.out.println(" [CSV] Saved: " + data); }
}
class JsonProcessor extends DataProcessor {
protected String getProcessorName() { return "JSON"; }
protected String parse(String data) { return "[Parsed JSON]: " + data; }
protected boolean validate(String data) { return data != null && data.startsWith("{"); }
protected void save(String data) { System.out.println(" [JSON] Stored: " + data); }
protected void notifyComplete(String data) { System.out.println(" [JSON] Published to event bus"); }
}
public class Main {
public static void main(String[] args) {
DataProcessor csv = new CsvProcessor();
csv.process("a,b,c");
DataProcessor json = new JsonProcessor();
json.process("{\"key\": \"value\"}");
json.process("invalid"); // Validation fails
}
}Review
Help Us Improve
How helpful was this walkthrough?
Click a star to rate. We actively use this feedback to refine and update our system design content.
Placeholder
Discussion
Share your thoughts, ask questions, or help others.
Loading comments...