Define the skeleton of an algorithm in a base class, deferring some steps to subclasses — subclasses can redefine certain steps without changing the algorithm's structure.
Template Method defines the overall structure of an algorithm in a base class method (the template method), and lets subclasses override specific steps without changing the skeleton. The base class controls the flow; subclasses provide the details.
This is the classic example of the Hollywood Principle: "Don't call us, we'll call you" — the base class calls the subclass methods, not the other way around.
You have a data mining application that processes reports from different formats (CSV, XML, PDF). Each format has different parsing and extracting logic, but the overall process is: open file → parse → extract data → analyse → send report. That pipeline is identical for all formats.
Without Template Method: duplicate the pipeline in every format class. With Template Method: put the pipeline in the base class, override only the format-specific steps in subclasses.
// AbstractClass — defines the template public abstract class DataMiner { // THE TEMPLATE METHOD — final: subclasses must NOT override public final void mine(String path) { String rawData = openFile(path); // concrete String data = extractData(rawData); // abstract — must override String parsed = parseData(data); // abstract — must override analyzeData(parsed); // concrete (shared logic) if (shouldSendReport()) { // hook — optional sendReport(parsed); // concrete } closeFile(path); // concrete } // Concrete steps — shared by all subclasses private String openFile(String path) { System.out.println("Opening: " + path); return "raw data from " + path; } private void analyzeData(String data) { System.out.println("Analyzing: " + data); } private void sendReport(String data) { System.out.println("Sending report for: " + data); } private void closeFile(String path) { System.out.println("Closing: " + path); } // Abstract steps — MUST be overridden by subclasses protected abstract String extractData(String raw); protected abstract String parseData(String data); // Hook — OPTIONAL override. Default: always send report protected boolean shouldSendReport() { return true; } } // ConcreteClass A — CSV format public class CSVDataMiner extends DataMiner { protected String extractData(String raw) { System.out.println("Extracting CSV columns"); return "csv_data"; } protected String parseData(String data) { System.out.println("Parsing CSV rows"); return "csv_parsed"; } // does NOT override shouldSendReport — uses default (true) } // ConcreteClass B — XML format, overrides hook public class XMLDataMiner extends DataMiner { private boolean debugMode; public XMLDataMiner(boolean debug) { this.debugMode = debug; } protected String extractData(String raw) { System.out.println("Extracting XML nodes"); return "xml_data"; } protected String parseData(String data) { System.out.println("Parsing XML elements"); return "xml_parsed"; } // Override hook — suppress report in debug mode protected boolean shouldSendReport() { return !debugMode; } } // Client — calls the template method public class Main { public static void main(String[] args) { DataMiner csvMiner = new CSVDataMiner(); csvMiner.mine("data.csv"); // runs full pipeline DataMiner xmlMiner = new XMLDataMiner(true); xmlMiner.mine("data.xml"); // skips report (debug mode) } }
java.util.AbstractList — get() and size() are abstract; iterator() and contains() use them in template methodsJdbcTemplate — template method for DB operations; callback supplies the SQL-specific partAbstractController — handleRequest() is the template; handleRequestInternal() is overriddensetUp(), test method, tearDown() is a classic template method lifecycleHttpServlet — service() dispatches to doGet(), doPost() which subclasses overridefinal, a subclass overrides the entire algorithm skeleton — the controlled structure is lost entirelyUnsupportedOperationException — the base class template method crashes mid-runpublic final void templateMethod() — makes it impossible for subclasses to override the skeleton, only the designated stepsprivate — subclasses cannot call them out of order and the template retains full control// ❌ BREAKING — template method not final, subclass overrides it public void mine(String path) { // ❌ not final /* skeleton */ } public class RogueSubclass extends DataMiner { public void mine(String path) { // ❌ completely replaces the template! extractData(path); // skips analysis, skips close — template structure destroyed } protected String extractData(String r) { return ""; } protected String parseData(String d) { return ""; } } // ✅ FIX — final template method cannot be overridden public final void mine(String path) { // ✅ final — skeleton protected openFile(path); extractData(path); analyzeData(path); closeFile(path); } // ❌ BREAKING — abstract step throws instead of implementing public class LazySubclass extends DataMiner { protected String extractData(String r) { throw new UnsupportedOperationException(); // ❌ base class crashes mid-run } protected String parseData(String d) { return ""; } } // ✅ FIX — abstract contract must be implemented properly // Document with Javadoc what the method MUST do: /** * Extracts raw fields from source data. * Must return non-null String. Never throw. */ protected abstract String extractData(String raw); // ❌ BREAKING — concrete steps not private, subclass calls out of order protected void openFile(String p) { /* ... */ } // ❌ protected — callable by subclass public class BrokenSubclass extends DataMiner { protected String extractData(String r) { openFile("extra.csv"); // ❌ calling a step out of sequence return ""; } } // ✅ FIX — concrete steps are private private String openFile(String p) { return ""; } // ✅ subclass cannot call this
final method calling abstract and hook methods. Subclasses provide implementations for abstract steps and optionally override hooks. Base class calls subclass — Hollywood Principle.