Template Method Design Pattern

Template Method Design Pattern | The template design pattern defines the skeleton of an algorithm in the superclass to complete a task or job leaving some operations to implement for the subclasses. 

Ultimately superclass defines the algorithm but it doesn’t implement every operation. The operations which are not common will be defined by subclass only. 

If we see the dictionary meaning of template then it represents a format, used as a starting point for a particular application so that the format does not have to be recreated each time it is used. The template method design pattern is based on the same idea. 

Assume we have a task, and to complete this task a(), b(), c(), d() methods are required in the given order. Here we should remember the method names and their order of invocation. But if we define an m1() method which internally calls those methods in the given order then to complete the task we just need to call the m1() method. Here, we don’t need to remember their invocation orders and the method names.

public void m1() {
   a();
   b();
   c();
   d();
}

Template method take care of:- 

  • Either all operations to complete the task.
  • Or take care of the common operation to complete the task and leave uncommon operations for the subclass to implement them to complete the task. 

The template method is the method of superclass having a series of methods to invoke to complete the task. In those methods, common operations/logics-related methods will be defined by the superclass itself. But gives specific operations-related methods to subclasses to override and to define logic as needed by subclasses.

  • Requirement:- Assume we have a series of functionality to be invoked in a particular order and few functionalities are common where are few functionalities are implementation-dependent.
  • Problem:- Remembering multiple method names and their sequence of invocation that are required to complete the certain task is a complex and error-prone process.
  • Solution:- Work with Template design pattern, where one Java method definition contains all the multiple method calls in sequence. So programmer needs to call only one Java method to complete the task.

The intent of Template design pattern:-

  • Define the skeleton of an algorithm in an operation, deferring some steps to subclasses.
  • Template method lets subclasses redefine certain steps of an algorithm without letting them to change the algorithm’s structure.

Difference between Factory Method Pattern vs Template Method Pattern

In the factory method pattern, we take one superclass which provides rules and guidelines. The sub-classes which are implementing that superclass must follow those rules. The sub-classes can’t add/remove/skip/modify any standard.

In the template pattern, the sub-classes which are implementing the superclass can modify/add/remove/skip the template. We can understand it through our resume template. Assume we downloaded one resume template from the internet, then we won’t continue with the same. We will take that template, remove the unnecessary details, add the required information, and we can do whatever things we want because there is no restriction available. See more here:- Factory Method Design Pattern.

Template Method Design Pattern Example

Let us take an example of an IT company that usually hires freshers in their organization. The hiring could in 2 formats i.e. a fresher can be deployed in any technology or a fresher who is already trained in some technology like Java, Python, UI will be deployed in that particular technology. If the company is small then they will prefer to get readily trained Java, Python, UI freshers. For both of them aptitude tests, Group discussions, HR rounds are common. However, they will have their own technical round and System test round. But the important point here is there is a proper sequence of all these rounds, and the sequence is:- An aptitude test => Group discussion => Technical test => System test => HR. From the client application, we will have to call these methods in sequence, and if you change the sequence, it will be impacted. 

To solve this problem, the template method design pattern can be used where we have to define a method (template method) that contains the method call in a sequence. Now the client application needs to call only that method, and since that method contains the format or pattern of call therefore it is called a template method. 

The algorithm for the recruitment process:-

  1. Aptitude Test
  2. Group Descission Test
  3. Technical Test
  4. Coding Test
  5. HR Test
// abstract superclass
public abstract class HireFresher {
   
   public boolean aptitudeTest() {...} // return true if passed
   public boolean GDTest() {...}  // return true if passed
   public abstract boolean technicalTest();
   public abstract boolean codingTest();
   public boolean hrTest() { ... } // return true if passed

   // template method
   // declare it as final so that child class can’t modify the order
   public final boolean recruitFreshers() {
      if(aptitudeTest()) {
        if(GDTest()) {
            if(technicalTest()) {
                if(codingTest()) {
                    if(hrTest()) {
                        return true;
                    }
                }
            }
        }
      }
      return false;
   } 
}

Subclass1,

public class HireJavaFreshers extends HireFresher {

   public abstract boolean technicalTest() {
      // logic to conduct Java technical test
      return true;
   }

   public abstract boolean codingTest() {
      // logic to conduct Java system test
      return true;
   }
}

Subclass2,

public class HirePythonFreshers extends HireFresher {

   public abstract boolean technicalTest() {
      // logic to conduct Python technical test
      return true;
   }

   public abstract boolean codingTest() {
      // logic to conduct Python system test
      return true;
   }
}

Template Method Design Pattern Code Example

Template Method Design Pattern Problem | First let us see what will be the problem when we code normally without using the Template method design pattern, after that we will see how we can solve it using the Template method design pattern. 

The project structure,

TemplateMethodDP-Problem
  => com.kp.comp
    => HireFresher.java (AC)
    => HireJavaFresher.java
    => HirePythonFresher.java
    => HireUIFresher.java
  => com.kp.test
    => Collage1PlacementCell.java

See the problem-code at GitHub:- TemplateMethodDP-Problem

Following are the main problems: in the above project for the In the project, client application developer (com.kp.test classes)-

  • They must know the algorithm to conduct hiring, and they have to call all those methods in their respective order. 
  • By mistake (possibility is there) they can change the order of method invocation or they may forget to invoke some method.
  • They have to know how to create object for component classes.

Solution Using Template Method Design Pattern

Steps to implement Template Method Design Pattern:- Define an abstract class containing abstract method and concrete method. The concrete method is the method with common logic whereas abstract methods are the methods whose logic depends on the implementation class and will be defined in the child class.

TemplateMethodDP-Solution
  => com.kp.comp
    => HireFresher.java (AC)
    => HireJavaFresher.java
    => HirePythonFresher.java
    => HireUIFresher.java
  => com.kp.factory
    => HireFresherFactory.java
  => com.kp.test
    => Collage1PlacementCell.java
    => Collage2PlacementCell.java

HireFresher.java is an abstract class that contains logic for common methods for hiring and also contains definitions of the methods which will have different logic. Note:- we should define the template method should as the final method so that the child class will not be able to interchange the order or modify the logic.

package com.kp.comp;

public abstract class HireFresher {
   public boolean conductAptitudeTest() {
      System.out.println("HireFresher.conductAptitudeTest()");
      return true;
   }

   public boolean conductGDTest() {
      System.out.println("HireFresher.conductGDTest()");
      return true;
   }

   public abstract boolean conductTechnicalTest();

   public abstract boolean conductCodingTest();

   public boolean conductHRTest() {
      System.out.println("HireFresher.conductHRTest()");
      return true;
   }
   
   // template method - defining the skeleton of the algorithm
   public final boolean recruiteFresher() {
      if(conductAptitudeTest()) {
         if(conductGDTest()) {
            if(conductTechnicalTest()) {
               if(conductCodingTest()) {
                  if(conductHRTest()) {
                     return true;
                  }
               }
            }
         }
      }
      return false;
   }
}

HireJavaFresher, HirePythonFresher, and HireUIFresher are child class of HireFresher class, implementing conductTechnicalTest() and conductCodingTest() methods. Note:- In these classes we can override the existing methods (conductAptitudeTest(), conductGDTest(), and conductHRTest()) if we are not satisfied with the existing logic.

HireJavaFresher.java

package com.kp.comp;

public class HireJavaFresher extends HireFresher {

   @Override
   public boolean conductTechnicalTest() {
      System.out.println("HireJavaFresher.conductTechnicalTest()");
      return true;
   }

   @Override
   public boolean conductCodingTest() {
      System.out.println("HireJavaFresher.conductCodingTest()");
      return true;
   }

}

HirePythonFresher.java

package com.kp.comp;

public class HirePythonFresher extends HireFresher {

   @Override
   public boolean conductTechnicalTest() {
      System.out.println("HirePythonFresher.conductTechnicalTest()");
      return false;
   }

   @Override
   public boolean conductCodingTest() {
      System.out.println("HirePythonFresher.conductCodingTest()");
      return false;
   }

}

HireUIFresher.java

package com.kp.comp;

public class HireUIFresher extends HireFresher {

   @Override
   public boolean conductTechnicalTest() {
      System.out.println("HireUIFresher.conductTechnicalTest()");
      return true;
   }

   @Override
   public boolean conductCodingTest() {
      System.out.println("HireUIFresher.conductCodingTest()");
      return true;
   }

}

The HireFresherFactory class implements Factory Design Pattern and defines a getInstance() factory to create one of the HireFresher type class objects based on the input value.

package com.kp.factory;

import com.kp.comp.HireFresher;
import com.kp.comp.HireJavaFresher;
import com.kp.comp.HirePythonFresher;
import com.kp.comp.HireUIFresher;

public class HireFresherFactory {
   public static HireFresher getInstance(String fresherType) {
      if (fresherType.equalsIgnoreCase("java"))
         return new HireJavaFresher();
      else if (fresherType.equalsIgnoreCase("python"))
         return new HirePythonFresher();
      else if (fresherType.equalsIgnoreCase("ui"))
         return new HireUIFresher();
      else
         throw new 
         IllegalArgumentException("As of now we are not recruiting " 
         + fresherType + " freshers");
   }
}

Now let us see the user/client class that demonstrates the application.

package com.kp.test;

import com.kp.comp.HireFresher;
import com.kp.factory.HireFresherFactory;

public class Collage1PlacementCell {

   public static void main(String[] args) {
      HireFresher javaFresher = 
            HireFresherFactory.getInstance("java");
      boolean result = javaFresher.recruiteFresher();
      if (result)
         System.out.println("Java fresher is selected");
      else 
         System.out.println("Java fresher is not selected");
   }

}
package com.kp.test;

import com.kp.comp.HireFresher;
import com.kp.factory.HireFresherFactory;

public class Collage2PlacementCell {

   public static void main(String[] args) {
      HireFresher uiFresher = 
           HireFresherFactory.getInstance("ui");
      boolean result = uiFresher.recruiteFresher();
      if (result)
         System.out.println("UI fresher is selected");
      else
         System.out.println("UI fresher is not selected");
   }

}

See the solution code at GitHub:- TemplateMethodDP-Solution.

In HireFresherFactory, Collage1PlacementCell, and Collage2PlacementCell classes instead of hardcoding values “java”, “python”, “ui”, and e.t.c you can create an ENUM and use them as we had done in the Factory design pattern example using Enum where BikeType.java is an ENUM.

Application Areas of Template Method Design Pattern

The Template Method design pattern should be used:-

  • To implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behavior that can vary.
  • When refactoring is performed and common behavior is identified among classes. An abstract base class containing all the common code (in the template method) should be created to avoid code duplication.

An application framework allows us to inherit from a class or set of classes and create a new application, reusing most of the code in the existing classes and overriding one or more methods in order to customize the application to your needs. A fundamental concept in the application framework is the Template Method which is typically hidden beneath the covers and drives the application by calling the various methods in the base class (some of which you have overridden in order to create the application).

An important characteristic of the Template method is that it is defined in the base class and cannot be changed. It’s sometimes a private method but it’s virtually always final. It calls other base-class methods (the ones you override) in order to do its job, but it is usually called only as part of an initialization process (and thus the client programmer isn’t necessarily able to call it directly).

Pre-defined Methods acting as Template Method Design Pattern

  • All non-abstract methods of java.io.InputStream, java.io.OutputStream, java.io.Reader, and java.io.Writer.
  • All non-abstract methods of java.util.AbstractList, java.util.AbstractSet, and java.util.AbstractMap.
  • javax.servlet.http.HttpServlet (or jakarta.servlet.http.HttpServlet), all doXxx() methods by default sends a  HTTP 405 “Method Not allowed” error to the response. You are free to implement none or any of them.

Leave a Comment

Your email address will not be published. Required fields are marked *