The Template Method pattern defines the skeleton of an algorithm in a base class, letting subclasses override specific steps without changing the algorithm structure.

Problem

Multiple classes share the same algorithm structure but differ in specific steps.

Solution

  abstract class DataMiner {
    // Template method — defines the algorithm skeleton
    public final void mine(String path) {
        openFile(path);
        extractData();
        analyzeData();
        closeFile();
    }

    protected abstract void openFile(String path);
    protected abstract void extractData();
    protected void analyzeData() { // hook — optional override
        System.out.println("Default analysis");
    }
    protected abstract void closeFile();
}

class PDFMiner extends DataMiner {
    protected void openFile(String path) { System.out.println("Opening PDF: " + path); }
    protected void extractData() { System.out.println("Extracting PDF text"); }
    protected void closeFile() { System.out.println("Closing PDF"); }
}

class CSVMiner extends DataMiner {
    protected void openFile(String path) { System.out.println("Opening CSV: " + path); }
    protected void extractData() { System.out.println("Parsing CSV rows"); }
    protected void analyzeData() { System.out.println("CSV statistical analysis"); }
    protected void closeFile() { System.out.println("Closing CSV"); }
}
  

Template Method Structure

Element Description
Template method final method defining algorithm skeleton
Abstract methods Must be overridden by subclasses
Hook methods Optional override with default behavior
Concrete methods Shared implementation in base class

Java Examples

  // AbstractList provides template for get/set/size
abstract class AbstractList<E> {
    public boolean add(E e) { add(size(), e); return true; } // template
    abstract public E get(int index);    // primitive
    abstract public int size();          // primitive
}

// HttpServlet service method
protected void service(HttpServletRequest req, HttpServletResponse resp) {
    if (req.getMethod().equals("GET")) doGet(req, resp);
    else if (req.getMethod().equals("POST")) doPost(req, resp);
    // ...
}

// JUnit test lifecycle — @BeforeEach, @Test, @AfterEach
  

Hook Methods

Optional steps subclasses can override:

  abstract class Game {
    public final void play() {
        initialize();
        if (shouldShowIntro()) {  // hook
            showIntro();
        }
        runGameLoop();
        cleanup();
    }

    protected boolean shouldShowIntro() { return true; } // default: show intro
    protected void showIntro() { System.out.println("Welcome!"); }
    protected abstract void runGameLoop();
}
  

Template Method vs Strategy

Template Method Strategy
Inheritance-based Composition-based
Fixed algorithm skeleton Entire algorithm swappable
Compile-time binding Runtime binding
“Is-a” relationship “Has-a” relationship

When to Use

  • Subclasses share a common algorithm with varying steps
  • You want to control which steps are overridden (use final template method)
  • Code reuse through inheritance is acceptable

Best Practices

  • Mark the template method as final to prevent altering the algorithm structure
  • Provide hook methods instead of abstract methods when override is optional
  • Prefer composition (Strategy) when runtime flexibility is needed
  • Keep the number of abstract methods small — too many reduces usefulness