Design Patterns Series 11 - Template Method Pattern

This post and the next will be about two patterns that give you clever ways of dealing with adapting the process of creating objects: The Template Method Pattern and Builder Pattern.

The Template Method Pattern:

The Template Method pattern lets sub-classes redefine the steps involved in creating an object.The Template Method will "define the skeleton of an algorithm in an operation, deferring some steps to sub-classes. Template Method lets sub-classes redefine certain steps of an algorithm without changing the algorithm structure."

You should use the Template Method pattern when you have an algorithm that is made of multiple steps, and you want to be able to customize some of those steps. Note That if you want to rewrite everything from scratch every time - if every step has to be customized by writing it from scratch - then you have no need of a template. Only if you have steps that are shared by various implementations of the algorithm do you need to work with template.

If you working for tourism company and they asked you to build an e-booking system for flights and hotels. You asked your manager about the steps of booking process, he told you that for flights or hotels we validate credit card, check cardholder, check card balance, validate the selected trip for flights and validate selected room for hotels, Do booking, and Confirm booking code.In that time you screamed that is the time of Template method pattern.

As you see the booking process for hotels and for flights share the same steps but some steps need to be customized according to hotels or flights. To implement the Template method Pattern we will create an abstract class called Booking with the required method for booking process, CheckValidCreditCard(), CheckCardHolder(), CheckCardBalance(), CheckValidBooking(), DoBooking(), BookingConfirmationCode(), and Book() method that define the Booking algorithm for flights and hotels.

Booking class
public abstract class Booking
{
    public virtual void CheckValidCreditCard()
    {
        Console.WriteLine("Checking valid credit card....");
    }

    public virtual void CheckCardHolder()
    {
        Console.WriteLine("Checking Credit card holder....");
    }

    public virtual void CheckCardBalance()
    {
        Console.WriteLine("Checking Credit Card Balance....");
    }

    public virtual void CheckValidBooking()
    {
        Console.WriteLine("Checking valid booking....");
    }

    public virtual void DoBooking()
    {
        Console.WriteLine("Do Booking....");
    }

    public virtual void BookingConfirmationCode()
    {
        Console.WriteLine("Confirm Booking....");
    }

    public void Book()
    {
        CheckValidCreditCard();
        CheckCardHolder();
        CheckCardBalance();
        CheckValidBooking();
        DoBooking();
        BookingConfirmationCode();
    }
}                                        
Note we defined the Booking class as abstract class and all method as virtual to be overridable with a default implementation except Book() method not defined as virtual method because this method defines the steps of booking algorithm that you cannot customize.

Now we will create two classes, FlightBooking to book flights and HotelBooking to book hotels. Both will inherit Booking class and override some methods that need to customize.

HotelBooking class
public class HotelBooking : Booking
{
    public String Name { get; set; }

    public HotelBooking(String name)
    {
        this.Name = name;
    }
    public override void CheckValidBooking()
    {
        Console.WriteLine("Validate selected room....");
    }
    public override void DoBooking()
    {
        Console.WriteLine("Do Hotel Booking....");
    }
    public override void BookingConfirmationCode()
    {
        Console.WriteLine("Confirm Hotel Booking....");
    }
}
FlightBooking class
public class FlightBooking : Booking
{
    public String Name { get; set; }

    public FlightBooking(String name)
    {
        this.Name = name;
    }

    public override void CheckValidBooking()
    {
        Console.WriteLine("Validate selected trip....");
    }

    public override void DoBooking()
    {
        Console.WriteLine("Do Flight Booking....");
    }

    public override void BookingConfirmationCode()
    {
        Console.WriteLine("Confirm Flight Booking....");
    }
}
Now you implemented the Template Method algorithm. Note we don't override all methods, if we did, it will not be Template method pattern. Let's test it and see if we implemented it correctly or not.
HotelBooking hBooking = new HotelBooking("Hotels");
Console.WriteLine(hBooking.Name +" : ");
hBooking.Book();

Console.WriteLine("*********************************************");

FlightBooking fBooking = new FlightBooking("Flights");
Console.WriteLine(fBooking.Name + " : ");
fBooking.Book();
In first section we created HotelBooking object and called the Book() method. That will call the Book() method of base class(Booking) which will call CheckValidCreditCard(), CheckCardHolder(),and CheckCardBalance() methods of base class and CheckValidBooking(), DoBooking(), and BookingConfirmationCode() methods of derived class(HotelBooking). The same thing in the second section but with the FlightBooking object. The outpout will be
Hotels :
Checking valid credit card....
Checking Credit card holder....
Checking Credit Card Balance....
Validate selected room....
Do Hotel Booking....
Confirm Hotel Booking....
*********************************************
Flights :
Checking valid credit card....
Checking Credit card holder....
Checking Credit Card Balance....
Validate selected trip....
Do Flight Booking....
Confirm Flight Booking....
Note the first three lines in hotel section and flight section are the same because we didn't customize these steps, but the next three lines in both section are different.

Adding a Hook:

A hook is a method that controls some aspect of the algorithm. If you wanted to make some part of the algorithm optional, you could surround that part with a conditional whose condition is set by a hook method.

To see how it work consider we don't need the last step in booking algorithm with hotel booking, so we need someway to skip it in hotel and do it in flights. First we will add a new virtaul method to base class -  Booking - , that return Boolean value.
public abstract class Booking
{
   ....
   public virtual Boolean DoConfirmation()
   {
      return true;
   }
   public void Book()
   {
      CheckValidCreditCard();
      CheckCardHolder();
      CheckCardBalance();
      CheckValidBooking();
      DoBooking();
      if(DoConfirmation())
      {
         BookingConfirmationCode();
      }
   }
}
By default it return true but for hotel we will override it to return false to skip the last step.
public class HotelBooking : Booking
{
   ....
   public override Boolean DoConfirmation()
   {
      return false;
   }
}
If we run the sample code again the output will be
Hotels :
Checking valid credit card....
Checking Credit card holder....
Checking Credit Card Balance....
Validate selected room....
Do Hotel Booking....
*********************************************
Flights :
Checking valid credit card....
Checking Credit card holder....
Checking Credit Card Balance....
Validate selected trip....
Do Flight Booking....
Confirm Flight Booking....
Note the last line in flight section doesn't exist in hotel section.

There you have it - you didn't have to do anything with the hook, but if you did, you can affect the execution of the algorithm. If you build your algorithm using a succession of abstract methods, each of these methods has to be overridden in a sub-class; hooks in the other hand, don't have to be overridden at all, unless you want to change the default execution of the algorithm.

You see the Template Method pattern when you have got an algorithm of several steps and you want to allow customization by sub-classes. Implement the steps in that algorithm as an overridable method calls in an abstract class, and let the sub-classes override those steps as required. The Template Method pattern is great when you have a multi-step algorithm to implement that you also want to customize.

you can download the full source code here

Comments

Popular posts from this blog

ASP.Net MVC : ActionLink with bootstrap icon

ASP.Net MVC : Conditional Validation using ValidationAttribute

Android : How to change progress bar color at runtime programmatically?