Template Method Design Pattern in Java with Real-World Examples

Template Method Design Pattern in Java: Complete Guide with Payment Example

Template Method Design Pattern in Java: Complete Guide with Real-World Examples

Have you ever noticed that different payment methods follow almost the same process?

For example, whether a customer makes a payment using UPI, a debit card, or a wallet, the application generally performs these steps:

  1. Validate the payment request.
  2. Check payment conditions.
  3. Execute the payment.
  4. Save the transaction details.
  5. Send a notification.

The overall payment process remains almost the same, but the actual payment execution changes depending on the payment method.

Now imagine writing this complete workflow separately for every payment method. You would probably end up with duplicated code.

The Template Method Design Pattern in Java solves exactly this problem. It defines the overall algorithm in a parent class and allows subclasses to customize individual steps.

In this guide, we will understand the pattern using a tea-and-coffee example and a real-world payment processing scenario, implement complete executable Java code, explore a Spring Boot use case, compare it with Strategy, and prepare for common Java design-pattern interview questions.

1. What Is the Template Method Design Pattern?

The Template Method pattern is a behavioral design pattern that defines the skeleton of an algorithm in a superclass. Some steps are implemented in the parent class, while other steps are left to subclasses.

The important point is that the parent class controls the execution order.

In simple words: The parent class decides what happens and in which order. The child class decides how certain steps happen.

Real-world example: Preparing tea and coffee

Think about preparing tea and coffee. Both follow a common process:

  1. Boil water.
  2. Add the main ingredient.
  3. Add milk or other ingredients.
  4. Serve the drink.

However, the ingredients are different. For tea, we add tea leaves. For coffee, we add coffee powder. The overall preparation process remains the same, but certain steps change.

This is the basic idea behind the Template Method Pattern.

Key participants

  • Abstract Class: Defines the template method and common steps.
  • Template Method: Defines the fixed sequence of operations.
  • Concrete Class: Implements the steps that vary.
  • Hook Method: An optional method with a default implementation that subclasses can override.

2. Important Components of the Pattern

The pattern has four key building blocks.

1. Abstract Class

Defines the template method and common steps. It may declare abstract methods for steps that subclasses must provide and concrete methods for steps that are shared.

2. Template Method

Defines the fixed sequence of operations. It usually calls common methods, abstract methods, and optional hook methods in a specific order. Making it final prevents subclasses from changing the sequence.

3. Concrete Class

Implements the steps that vary between different variants of the algorithm. For example, UPIPayment, CardPayment, and WalletPayment provide their own executePayment() implementations.

4. Hook Method

An optional method that subclasses can override to customize a step. It has a default implementation in the parent class, so subclasses that do not need customization can simply ignore it.

3. Template Method Class Diagram

This original diagram shows how an abstract payment class defines the common workflow, while UPI, card, and wallet payment classes provide their own payment implementation.

Template Method Class Diagram with UPI, Card, and Wallet Subclasses AbstractPayment defines the final processPayment() template method, a private validatePayment() step, an abstract executePayment() method, and an overridable beforePayment() hook. UPIPayment, CardPayment, and WalletPayment extend AbstractPayment and provide their own executePayment() implementations. WalletPayment also overrides the beforePayment() hook. AbstractPayment + processPayment() : void [final] - validatePayment() : void # executePayment() : void [abstract] # beforePayment() : void [hook] UPIPayment executePayment() UPI-specific logic CardPayment executePayment() Card-specific logic WalletPayment executePayment() Wallet-specific logic Three subclasses · One common template All subclasses inherit processPayment()
Figure: The abstract parent class defines the workflow, and concrete subclasses provide their own step implementations.

Important: The abstract class contains the common workflow. Each child class provides its own implementation of executePayment(). The wallet class can additionally override the optional hook method.

4. How the Template Method Works Internally

Let's understand the execution sequence.

  1. The client creates an object of a concrete payment class.
  2. The client calls processPayment().
  3. The parent class validates the payment request.
  4. The parent class calls beforePayment().
  5. The child class implementation of executePayment() is invoked.
  6. The parent class saves the transaction and sends a notification.

The important point is that the client never assembles the workflow itself. The parent class owns the sequence, and the subclass only supplies the pieces that differ.

What changes after introducing a template method?

The common steps live in one place. Each concrete subclass contains only the implementation of the specific steps that vary. Adding a new payment method becomes a matter of adding a new subclass rather than duplicating the whole workflow.

5. Execution Flow Diagram

This diagram represents the common sequence followed by UPI, card, and wallet payments. Only the payment execution implementation changes.

Template Method Payment Execution Flow The client calls processPayment(), which validates the request, runs the beforePayment() hook, executes the subclass-specific payment step, saves the transaction, and sends a notification. The parent class controls the execution order. Client calls processPayment() 1. Validate payment request 2. Run beforePayment() hook 3. Execute payment (subclass) UPIPayment UPI execution CardPayment Card execution WalletPayment Wallet execution 4. Save transaction 5. Send notification
Figure: The template method runs the workflow in a fixed order, delegating the payment execution step to the subclass.

The parent class controls the sequence before and after payment execution. The child class only supplies the payment-specific behavior.

6. Java Implementation – Tea and Coffee Example

Before implementing a payment system, let's create a simple example using tea and coffee. This example makes the pattern easy to see before applying it to a real workflow.

Complete executable Java code

Create a file named BeverageDemo.java and copy the following code.

abstract class Beverage {

    // Template Method
    public final void prepareBeverage() {
        boilWater();
        addMainIngredient();
        addCondiments();
        serve();
    }

    private void boilWater() {
        System.out.println("Boiling water...");
    }

    protected abstract void addMainIngredient();

    protected abstract void addCondiments();

    private void serve() {
        System.out.println("Serving beverage...");
    }
}

class Tea extends Beverage {

    @Override
    protected void addMainIngredient() {
        System.out.println("Adding tea leaves...");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding milk and sugar...");
    }
}

class Coffee extends Beverage {

    @Override
    protected void addMainIngredient() {
        System.out.println("Adding coffee powder...");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding milk and sugar...");
    }
}

public class BeverageDemo {

    public static void main(String[] args) {

        Beverage tea = new Tea();

        System.out.println("Preparing Tea:");
        tea.prepareBeverage();

        System.out.println();

        Beverage coffee = new Coffee();

        System.out.println("Preparing Coffee:");
        coffee.prepareBeverage();
    }
}

Expected output

Preparing Tea:
Boiling water...
Adding tea leaves...
Adding milk and sugar...
Serving beverage...

Preparing Coffee:
Boiling water...
Adding coffee powder...
Adding milk and sugar...
Serving beverage...

Understand this carefully: Both classes execute the same prepareBeverage() method. However, the implementation of addMainIngredient() and addCondiments() comes from the respective child class.

Also notice the final keyword. It prevents subclasses from overriding the template method and changing the overall sequence.

7. Real-World Example – Payment Processing System

Now let's understand a practical example from a fintech application.

Suppose you are developing a payment gateway that supports three payment methods:

  • UPI payment
  • Debit or credit card payment
  • Wallet payment

All three methods need common processing steps, but each payment method has its own execution logic. Without a proper design, developers may write the same validation, transaction-saving, and notification code in multiple classes.

Let's solve this problem using the Template Method Pattern.

Complete executable Java 8 code

For simplicity, we will simulate the payment providers using console messages. In a real application, the payment execution methods would communicate with external payment APIs or internal payment services.

Create a file named PaymentDemo.java.

abstract class AbstractPayment {

    private final double amount;

    public AbstractPayment(double amount) {
        this.amount = amount;
    }

    // Template Method
    public final void processPayment() {

        validatePayment();

        beforePayment();

        executePayment();

        saveTransaction();

        sendNotification();

        System.out.println("Payment completed successfully.");
    }

    private void validatePayment() {

        if (amount <= 0) {
            throw new IllegalArgumentException(
                "Payment amount must be greater than zero"
            );
        }

        System.out.println("Payment validation successful.");
    }

    // Optional hook method
    protected void beforePayment() {
        System.out.println("Checking payment conditions...");
    }

    // Subclasses implement their own payment logic
    protected abstract void executePayment();

    private void saveTransaction() {
        System.out.println("Saving transaction: Rs. " + amount);
    }

    private void sendNotification() {
        System.out.println("Sending payment notification...");
    }

    protected double getAmount() {
        return amount;
    }
}

class UPIPayment extends AbstractPayment {

    public UPIPayment(double amount) {
        super(amount);
    }

    @Override
    protected void executePayment() {
        System.out.println(
            "Processing UPI payment of Rs. " + getAmount()
        );
    }
}

class CardPayment extends AbstractPayment {

    public CardPayment(double amount) {
        super(amount);
    }

    @Override
    protected void executePayment() {
        System.out.println(
            "Processing Card payment of Rs. " + getAmount()
        );
    }
}

class WalletPayment extends AbstractPayment {

    public WalletPayment(double amount) {
        super(amount);
    }

    @Override
    protected void beforePayment() {
        System.out.println("Checking wallet balance...");
    }

    @Override
    protected void executePayment() {
        System.out.println(
            "Processing Wallet payment of Rs. " + getAmount()
        );
    }
}

public class PaymentDemo {

    public static void main(String[] args) {

        System.out.println("----- UPI PAYMENT -----");

        AbstractPayment upiPayment =
            new UPIPayment(1000);

        upiPayment.processPayment();

        System.out.println();

        System.out.println("----- CARD PAYMENT -----");

        AbstractPayment cardPayment =
            new CardPayment(2000);

        cardPayment.processPayment();

        System.out.println();

        System.out.println("----- WALLET PAYMENT -----");

        AbstractPayment walletPayment =
            new WalletPayment(500);

        walletPayment.processPayment();
    }
}

Let's understand the important code

1. Why is processPayment() final?

The processPayment() method is the template method. It defines the payment workflow. Making it final prevents subclasses from overriding the method and changing the required execution sequence.

2. Why is executePayment() abstract?

Because each payment method has a different implementation. UPI, card, and wallet payments may communicate with different services or providers.

3. Why is beforePayment() a hook method?

Not every payment method needs the same additional operation. The parent class provides a default implementation, and a child class can override it when necessary. In our example, the wallet payment checks its balance before executing the payment.

4. Why are saveTransaction() and sendNotification() common methods?

Because the basic transaction-saving and notification workflow is shared by all payment types in this simplified example. Therefore, we avoid duplicating these operations in every child class.

8. Payment Workflow Diagram

This original diagram shows the shared payment template and the three concrete payment implementations that plug into it.

Payment Template Method Workflow A common payment template defines the processPayment() sequence of validate, execute, save, and notify. UPI, card, and wallet payments plug into the execute step with their own implementations, while sharing the transaction and notification workflow. Common Payment Template processPayment() Validate → Execute → Save → Notify Same sequence for every payment type UPI Payment UPI provider API Custom execution Card Payment Card provider API Custom execution Wallet Payment Wallet service Custom execution Different implementations, same overall algorithm Common transaction and notification workflow
Figure: The shared payment template defines the workflow; each payment type only supplies its execution step.

9. Expected Output

----- UPI PAYMENT -----
Payment validation successful.
Checking payment conditions...
Processing UPI payment of Rs. 1000.0
Saving transaction: Rs. 1000.0
Sending payment notification...
Payment completed successfully.

----- CARD PAYMENT -----
Payment validation successful.
Checking payment conditions...
Processing Card payment of Rs. 2000.0
Saving transaction: Rs. 2000.0
Sending payment notification...
Payment completed successfully.

----- WALLET PAYMENT -----
Payment validation successful.
Checking wallet balance...
Processing Wallet payment of Rs. 500.0
Saving transaction: Rs. 500.0
Sending payment notification...
Payment completed successfully.

Notice that all three payments execute the same processPayment() template, but the executePayment() step changes for each payment method. The wallet payment also overrides the beforePayment() hook to check the balance.

How the responsibilities are separated

Component Responsibility
AbstractPayment Defines the workflow and common steps.
processPayment() Fixed template method controlling the execution sequence.
executePayment() Abstract step implemented by each concrete payment class.
beforePayment() Optional hook overridable by subclasses when needed.
UPIPayment / CardPayment / WalletPayment Provide their own execution logic.

10. Template Method in Spring Boot

The Template Method Pattern can be useful in Spring Boot applications when multiple services follow a common sequence of operations but have different implementations for one or more steps.

Some examples include:

  • Payment processing: Common validation, transaction handling, and notification workflow.
  • File processing: Read file, validate records, transform data, and save results.
  • Report generation: Load data, process records, generate a report, and export it.
  • Authentication: Common authentication flow with different authentication mechanisms.
  • Third-party integration: Common request preparation, provider-specific execution, and response handling.

Example: Spring Boot file processing

Suppose your Spring Boot application processes CSV and Excel files. Both file types follow a similar workflow:

  1. Read the file.
  2. Validate its contents.
  3. Transform the data.
  4. Save the records.

You can create an abstract processor that defines this workflow and separate CSV and Excel processors that implement the file-specific steps. This keeps common processing logic in one place.

Is this always the best design?

No. A class hierarchy is not always the right answer. If the workflow itself needs to change frequently, or if you need to select an algorithm at runtime, the Strategy pattern may be a better fit.

Production consideration: In a real Spring Boot application, also consider dependency injection, transaction boundaries, exception handling, retry policies, idempotency, and external API failure handling. A template method alone does not provide these capabilities.

11. Template Method vs Strategy Pattern

Both patterns help reduce duplicated code, but they solve different problems.

Comparison Template Method Strategy
Type Behavioral Behavioral
Approach Inheritance Composition
Algorithm Defines a fixed workflow Encapsulates interchangeable algorithms
Customization Subclasses override steps Different strategy implementations
Execution order Controlled by parent class Controlled by the calling object
Flexibility Suitable for fixed workflows Flexible for runtime selection

Template Method: Every payment follows the same sequence, but the payment execution step changes.

Strategy: The application selects a payment strategy, such as UPI, card, or wallet, and delegates payment execution to that strategy.

Template Method uses inheritance to vary individual steps of an algorithm. Strategy uses composition to replace an entire algorithm.

12. Advantages and Disadvantages of the Template Method Pattern

Advantages

  • Code reusability: Common logic is written once in the parent class.
  • Less code duplication: Subclasses implement only the steps that differ.
  • Consistent workflow: The parent class controls the sequence of operations.
  • Easy maintenance: Changes to common operations can be made in one place.
  • Controlled customization: Subclasses can customize only the permitted steps.

Disadvantages

  • Inheritance dependency: It relies on a parent-child relationship, which creates tight coupling.
  • Limited flexibility: Changing the workflow may require modifying the parent class.
  • More subclasses: Multiple variations can increase the number of classes.
  • Debugging complexity: Execution moves between parent and child methods, which can make debugging harder.
  • Subclass coupling: Child classes depend on the structure and protected methods of the parent class.

The best template method is small, focused, and stable. If the workflow begins to change frequently or needs to be selected at runtime, consider moving to a composition-based design instead.

13. Best Practices

  1. Keep the template method small and easy to understand. The sequence of steps should be readable at a glance.
  2. Use the final keyword when subclasses must not change the algorithm sequence.
  3. Keep common operations in the parent class. Avoid duplicating the same logic in each subclass.
  4. Use abstract methods only for steps that must be implemented by subclasses.
  5. Use hook methods for optional customization. Provide sensible defaults so subclasses can override only when necessary.
  6. Avoid adding too many customization points without a real requirement. More hooks increase complexity without adding value.
  7. Do not use inheritance just to share a few utility methods. Composition is usually a better fit for that case.
  8. Write unit tests for the common workflow and each concrete implementation. This ensures the sequence remains intact as the design evolves.

14. Java Interview Questions and Answers

Q1. What is the Template Method Design Pattern?

Template Method is a behavioral design pattern that defines the skeleton of an algorithm in a superclass and allows subclasses to implement or customize specific steps without changing the overall algorithm structure.

Q2. Why is Template Method called a behavioral design pattern?

Because it focuses on how an algorithm is executed and how responsibilities are distributed between the parent and child classes.

Q3. What is a template method?

A template method is the method that defines the sequence of steps of an algorithm. It usually calls common methods, abstract methods, and optional hook methods.

Q4. Why is the template method often declared final?

To prevent subclasses from overriding the workflow and changing the predefined order of execution. However, declaring it final is a design choice, not an absolute requirement of the pattern.

Q5. What is a hook method?

A hook method is an optional method with a default implementation in the parent class. Subclasses can override it to customize behavior when required.

Q6. What is the difference between an abstract method and a hook method?

An abstract method has no implementation in the abstract class and must be implemented by a concrete subclass. A hook method has a default implementation and can optionally be overridden.

Q7. Can we implement Template Method without an abstract class?

Yes. A concrete parent class can define the template method and allow subclasses to override protected methods. However, an abstract class is commonly used when some algorithm steps must be implemented by subclasses.

Q8. What is the difference between Template Method and Strategy?

Template Method uses inheritance and defines a fixed algorithm structure. Strategy uses composition and allows the application to select an interchangeable algorithm implementation.

Q9. Can a template method call private methods?

Yes. The template method can call private methods for operations that must remain internal to the parent class. Subclasses cannot override those private methods.

Q10. Can a subclass change the execution order?

If the template method is final, the subclass cannot override the workflow. It can only customize the steps that the parent class exposes for customization.

Q11. What is the Hollywood Principle in relation to Template Method?

The Hollywood Principle means "Don't call us, we'll call you." The parent class controls the algorithm and calls the subclass methods when necessary. Subclasses do not control the overall workflow.

Q12. Is Template Method suitable for microservices?

It can be useful inside a microservice when multiple workflows share common steps. For example, different file processors or payment handlers may share a common processing sequence. It does not replace communication or orchestration between microservices.

Q13. Can Template Method be used with Spring Boot?

Yes. An abstract Spring-managed service can define a common workflow, while concrete Spring components implement the specific steps. Dependency injection can be used for supporting services.

Q14. What happens if a subclass does not implement an abstract method?

The subclass must either implement the abstract method or remain abstract. Otherwise, Java compilation fails.

Q15. When should we avoid Template Method?

Avoid it when the steps of the algorithm change frequently, when you need to select algorithms dynamically at runtime, or when inheritance creates unnecessary coupling. Strategy or composition may be a better choice in such cases.

15. Frequently Asked Questions

Is Template Method part of Java?

No. It is a design pattern, not a built-in Java API. You can implement it using Java classes, inheritance, and method overriding.

Is Template Method the same as a Java template class?

No. Java does not have C++-style templates. Template Method is a design pattern implemented through inheritance and polymorphism.

Can we use interfaces for Template Method?

An interface with default methods can provide some similar behavior, but an abstract class is generally more suitable when you need shared state, constructors, protected methods, and abstract steps.

Where is Template Method useful in real projects?

It is useful in payment processing, file processing, report generation, authentication workflows, and third-party integrations where the overall sequence is common but individual steps differ.

Is the Template Method pattern part of the Gang of Four patterns?

Yes. Template Method is one of the behavioral patterns in the Gang of Four design-pattern catalog.

Does Template Method mean all steps must be fixed?

No. The sequence is fixed, but individual steps can be implemented, overridden, or optionally skipped through hooks depending on the design.

16. Quick Revision Checklist

  • Template Method is a behavioral design pattern.
  • It defines the skeleton of an algorithm in a superclass.
  • The template method controls the execution order.
  • Subclasses customize specific steps without changing the sequence.
  • Making the template method final protects the workflow.
  • Hook methods provide optional customization with sensible defaults.
  • Payment processing, file processing, and report generation are typical uses.
  • Template Method uses inheritance; Strategy uses composition.
  • Spring Boot services can use it for common workflows across concrete components.
  • Avoid it when the workflow changes frequently or must be selected at runtime.

Conclusion

The Template Method Design Pattern is useful when multiple classes follow the same algorithm but need different implementations for certain steps. Instead of duplicating the entire workflow, we define the common sequence in a parent class and let subclasses customize only the required operations.

Remember these three important points:

  • The parent class defines the algorithm structure.
  • Child classes customize specific steps.
  • The template method controls the execution order.

Before using this pattern in a real project, check whether your workflow is genuinely common. If the entire algorithm needs to change dynamically, consider the Strategy Pattern instead.

If you are preparing for Java interviews, practise implementing Template Method alongside Strategy, Observer, and Factory Method. Understanding when each pattern is useful matters more than memorizing its definition.

No comments: