Template method pattern is one of the behavioral design patterns. I think that you all must have already used this pattern many times.
In this pattern, Abstract class holds the primitive operations which needs to be executed and all those methods might be abstract if they are customizable and it also holds one method which executes all the other methods in pattern which you have defined. This method is also called template method. This abstract class must be overridden by sub classes to write custom primitive operations according to your requirements.
We can understand this pattern by following code.
import abc class AbstractClass(metaclass=abc.ABCMeta): @abc.abstractmethod def operation_1(self): pass @abc.abstractmethod def operation_1(self): pass @abc.abstractmethod def template_method(self): self.operation_1() self.operation_2() class RealClass1(AbstractClass): @abc.abstractmethod def operation_1(self): print("Real operation 1) @abc.abstractmethod def operation_1(self): print("Real operation 1) obj = RealClass1() obj.template_method() # Output : # Real operation 1 # Real operation 2
In this sample code, You can see
AbstractClass holds two operation method which are abstract methods and one
template_method which executes both the operations. Now if you see RealClass1 overrides two operation methods according to requirements. Further, if you create object of
RealClass1 and call
template_method method which will execute both operations which are written in sub class. That way you can build many other sub classes as per different requirements.
Now let's understand with real life example of trip planning.
We have one trip planner and he has multiple packages of three days trips. Now how he create the itinerary for the customers. Suppose customer wants to go south or north then according to that planner will give him the package. Now lets see how he plans/executes without doing duplicate work. Planner has already one base format where he needs to mention how traveler will travel to destination, what they will do there on day 1,2 and 3 and at last how they will travel to back home.
Let's write base class
ThreeDaysTrip which already knows how to execute the trip.
import abc class ThreeDaysTrip(metaclass=abc.ABCMeta): @abc.abstractmethod def transport(self): pass @abc.abstractmethod def day1(self): pass @abc.abstractmethod def day2(self): pass @abc.abstractmethod def day3(self): pass @abc.abstractmethod def back_to_home(self): pass def itinerary(self): print("Trip is started") self.transport() self.day1() self.day2() self.day3() self.back_to_home() print("Trip is over")
By extending this base class, we are going to write two more class with different locations and different itinerary which will be used to execute two different trips.
class SouthTrip(ThreeDaysTrip): def transport(self): print("Go by train! check in to hotel") def day1(self): print("Day-1: Enjoy the hotel beach whole day") def day2(self): print("Day-2: Visit historical places and Enjoy cruise life at night") def day3(self): print("Day-3: Enjoy shopping day with family and go anywhere you wish") def back_to_home(self): print("Check out and go Home by air!") class NorthTrip(ThreeDaysTrip): def transport(self): print("Go by air! check in to hotel") def day1(self): print("Day-1: Go to very highted place and enjoy snow activities") def day2(self): print("Day-2: Enjoy river rafting and lavish dinner at night") def day3(self): print("Day-3: Enjoy shopping day with family and go anywhere you wish") def back_to_home(self): print("Check out and go Home by air!")
In above code, You can see two classes NorthTrip and SouthTrip both are three days trip but process is very much similar of executing the whole trip. So all the abstract methods are overridden as per need of both the trips. This way if you are planning to start new trip in different direction then you need to write one more class and just add the itinerary.
Now let's look at the planners code how that will use above classes.
if __name__ == "__main__": place = input("Where do you want to go? ") if place == 'north': trip = NorthTrip() trip.itinerary() elif place == 'south': trip = SouthTrip() trip.itinerary() else: print("Sorry, We do not have any trip towards that place!")
As you can see, planner is asking for the place where customer wants to go and according to that he calls the different class. If custom wants to go south side then
SouthTrip class is used. But if trip is not available the he straight forward will say sorry. :)
Certainly there are benefits of this pattern so let's look at the advantages.
- Reduction of code duplication
- As it uses inheritance, reusability of the code increases
- Steps execution of the process can be customized
When you see advantages of anything, there are always none to minor disadvantages along with it.
- As process execution is hold by base class, with more and more changes in the program maintainability becomes difficult.
- Sometimes, debugging becomes hard as execution is always happen in base class so writing better error handling can help.
I hope you have understood the pattern and its purpose. Thanks!