Skip to main content

Template Method Pattern

Overview

The Template Method pattern is a behavioral design pattern that defines the skeleton of an algorithm in a base class and lets subclasses override specific steps without changing the algorithm's structure. It enables you to reuse code while allowing for variations in certain steps.

Real-World Analogy

Think of a manufacturing process for different types of vehicles. The basic steps (create frame, install engine, add wheels, paint) remain the same, but the specific details vary for each vehicle type. The Template Method provides the basic sequence while allowing customization of individual steps.

Key Concepts

Core Components

  1. Abstract Class: Defines template method and abstract operations
  2. Concrete Classes: Implement the abstract operations
  3. Template Method: Defines the algorithm skeleton
  4. Hook Methods: Optional steps with default implementations

Implementation Example

// Abstract Class
abstract class DataMiner {
// Template method
public final void mine(String path) {
String data = extractData(path);
String processed = parseData(data);
String analyzed = analyzeData(processed);
sendReport(analyzed);
}

// Abstract steps
protected abstract String extractData(String path);
protected abstract String parseData(String data);

// Concrete steps
protected String analyzeData(String data) {
return "Analyzed: " + data;
}

// Hook method
protected void sendReport(String report) {
System.out.println(report);
}
}

// Concrete Implementation - CSV
class CSVDataMiner extends DataMiner {
@Override
protected String extractData(String path) {
System.out.println("Extracting data from CSV: " + path);
return "CSV data";
}

@Override
protected String parseData(String data) {
System.out.println("Parsing CSV data");
return "Parsed " + data;
}

@Override
protected void sendReport(String report) {
System.out.println("Sending CSV report via email: " + report);
}
}

// Concrete Implementation - PDF
class PDFDataMiner extends DataMiner {
@Override
protected String extractData(String path) {
System.out.println("Extracting data from PDF: " + path);
return "PDF data";
}

@Override
protected String parseData(String data) {
System.out.println("Parsing PDF data");
return "Parsed " + data;
}
}

// Advanced Template with Hooks
abstract class AdvancedDataMiner {
private final List<Consumer<String>> observers = new ArrayList<>();

public final void mine(String path) {
beforeExtract(path);
String data = extractData(path);

if (shouldParse(data)) {
data = parseData(data);
}

if (shouldAnalyze(data)) {
data = analyzeData(data);
}

notifyObservers(data);
afterAnalysis(data);
sendReport(data);
}

// Hook methods
protected void beforeExtract(String path) {}
protected boolean shouldParse(String data) { return true; }
protected boolean shouldAnalyze(String data) { return true; }
protected void afterAnalysis(String data) {}

// Abstract methods
protected abstract String extractData(String path);
protected abstract String parseData(String data);
protected abstract String analyzeData(String data);
protected abstract void sendReport(String report);

// Observer support
public void addObserver(Consumer<String> observer) {
observers.add(observer);
}

private void notifyObservers(String data) {
observers.forEach(o -> o.accept(data));
}
}
  1. Strategy Pattern

    • Template Method uses inheritance, Strategy uses composition
    • Template Method is best for fixed algorithms with variable steps
    • Strategy is better for interchangeable algorithms
  2. Factory Method

    • Often used within Template Methods
    • Creates objects whose exact types are decided by subclasses
  3. Observer Pattern

    • Can be used to notify about step completion
    • Useful for monitoring template method execution

Best Practices

Configuration

  1. Make template method final
  2. Clearly document which methods must be overridden
  3. Use hook methods for optional steps

Monitoring

  1. Log execution of each step
  2. Track performance metrics
  3. Monitor hook method usage

Testing

  1. Test each concrete implementation
  2. Verify hook method behavior
  3. Test step sequence

Common Pitfalls

  1. Breaking Template Method

    • Solution: Make template method final
    • Document method dependencies
  2. Deep Inheritance Hierarchies

    • Solution: Use composition when possible
    • Keep inheritance levels shallow
  3. Rigid Structure

    • Solution: Use hook methods for flexibility
    • Consider strategy pattern for variable algorithms

Use Cases

1. Data Processing Pipelines

  • ETL operations
  • Data validation
  • Report generation

2. Document Generation

  • Different format handling
  • Template processing
  • Custom rendering

3. Application Initialization

  • Startup sequences
  • Resource loading
  • Configuration setup

Deep Dive Topics

Thread Safety

public abstract class ThreadSafeTemplate {
private final ReentrantLock lock = new ReentrantLock();

public final void templateMethod() {
lock.lock();
try {
beforeHook();
step1();
step2();
afterHook();
} finally {
lock.unlock();
}
}

protected abstract void step1();
protected abstract void step2();

// Hook methods with default implementations
protected void beforeHook() {}
protected void afterHook() {}
}

Distributed Systems

  1. Distributed step execution
  2. Step synchronization
  3. Failure handling

Performance Considerations

  1. Step caching
  2. Lazy execution
  3. Resource pooling

Additional Resources

References

  1. "Design Patterns" by Gang of Four
  2. "Clean Code" by Robert C. Martin
  3. "Head First Design Patterns" by Freeman et al.

Tools

  1. IDE templates
  2. Code generation tools
  3. Performance monitoring tools

FAQ

Q: When should I use Template Method pattern?
A: Use it when you have:

  • An algorithm with fixed steps but flexible implementations
  • Common code that should be reused across similar classes
  • Control over the algorithm structure while allowing customization

Q: How is it different from Strategy pattern?
A: Template Method uses inheritance to vary parts of an algorithm, while Strategy uses composition to vary the entire algorithm.

Q: Can I have multiple template methods in a class?
A: Yes, but keep them focused and related to maintain single responsibility principle.

Q: Should hook methods be protected or public?
A: Generally protected, unless there's a specific need for public access.

Q: How do I handle optional steps?
A: Use hook methods with default implementations that can be overridden when needed.