Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Six common uses of the Template Design Pattern: Design Pattern series

4.95/5 (23 votes)
29 Dec 2011CPOL7 min read 115.4K  
In this article, we will learn about six common use of the Template Design Pattern.

Table of contents

Introduction and goal

In this article, we will try to understand six important uses of Template Design Pattern. The Template Design Pattern is one of those patterns which is used knowingly or unknowingly in many places. This article will flesh out six places where this pattern is seen evident.

Definition: The Template pattern is used in scenarios where we want to create extendable behaviors in generalization and specialization relationships.

If you are new to Design Patterns, you can start with looking at my Factory pattern video. It’s a pretty old video, so sorry about the quality, I was pretty novice when I started recording.

You can also see the References section at the end for my complete four part series on Design Patterns.

Introduction to the Template pattern

The Template pattern belongs to the behavioral pattern category. The Template pattern defines a main process template and this main process template calls sub-processes in a sequential manner. Later, the sub processes of the main process can be altered to generate a different behavior.

For example, below is a simple process to parse and load data into Oracle. The overall process has three fixed steps:

  • Load data from the source
  • Parse the data
  • Dump the data into Oracle

Image 1

Now you can alter the “Load” and “Parse” implementations to create a CSV file load process. The overall sequence of calling “Load”, “Parse”, and “Dump” will remain the same but we have the full liberty to change the implementation of “Load”, “Parse”, and “Dump”, thus creating a new process.

Image 2

You can see from the above figure how we have altered the ‘Load’ and ‘Parse’ sub processes to generate a CSV file and a SQL Server load process. The ‘Dump’ function and the sequence of how the sub-processes are called are not altered in the child processes.

In order to implement the Template pattern, we need to follow four important steps:

  1. Create the template or the main process by creating a parent abstract class.
  2. Create the sub-processes by defining abstract methods and functions.
  3. Create a method which defines the sequence of how the sub-process methods will be called. This method should be defined as a normal method so that child methods cannot override it.
  4. Finally create the child classes which can alter the abstract methods or sub-process to define a new implementation.
C#
public abstract class GeneralParser
{
    protected abstract void Load();

    protected abstract void Parse();
    protected virtual void Dump()
    {
        Console.WriteLine("Dump data in to oracle");
    }
    public void Process()
    {
        Load();
        Parse();
        Dump();
    }
}

SqlServerParser inherits from GeneralParser and overrides Load and Parse with a SQL Server implementation.

C#
public class SqlServerParser : GeneralParser
{
    protected override void Load()
    {
        Console.WriteLine("Connect to SQL Server");
    }
    protected override void Parse()
    {
        Console.WriteLine("Loop through the dataset");
    }
}

FileParser inherits from GeneralParser and overrides the Load and Parse methods with a file specific implementation.

C#
public class FileParser : GeneralParser
{
    protected override void Load()
    {
        Console.WriteLine("Load the data from the file");
    }
    protected override void Parse()
    {
        Console.WriteLine("Parse the file data");
    }
  
}

From the client, you can now call both the parsers.

C#
FileParser ObjFileParser = new FileParser();
ObjFileParser.Process();
Console.WriteLine("-----------------------");
SqlServerParser ObjSqlParser = new SqlServerParser();
ObjSqlParser.Process();
Console.Read();

The outputs of both the parsers are shown below:

Load the data from the file
Parse the file data
Dump data in to oracle
-----------------------
Connect to SQL Server
Loop through the dataset
Dump data in to oracle

Now let’s walk through some practical scenarios where the “Template” pattern can be implemented.

Scenario 1: Flexible extendable generalized specialized user interfaces

Many times we come across UIs which look almost tyhe same but with small differences in look and feel. For instance, in the below picture, the data is all the same for the screens, but the background colors are different.

Image 3

In this scenario, the form constructor will become the main process which will call three processes/functions:

  • InitializeComponent: This will create the UI objects needed for the form.
  • LoadCustomer: This function will load data and bind to the grid.
  • LoadGrid: This function will define the look and feel of the grid.
C#
public Form1()
{
    InitializeComponent();
    LoadCustomer();
    LoadGrid();
}

Below is the full code of the base form. Please note: LoadGrid is an abstract method. In other words, we can create forms with different color implementations without disturbing the rest of the form.

C#
public abstract partial class Form1 : Form
{
    protected Customers objCustomers = new Customers();
    protected List<customer> oCustomerList;
    public Form1()
    {
        InitializeComponent();
        LoadCustomer();
        LoadGrid();
    }

    public void LoadCustomer()
    {
        oCustomerList = objCustomers.GetCustomers();
    }
    public abstract void LoadGrid();
}

If you want to create a new form with a different background, you can keep the other code as is and just override the LoadGrid functionality with a different color / look and feel. Below is the sample code:

C#
public partial class Form3 : Form1
{
    ....
    ....
    ....
    ....
        public override void LoadGrid()
        {
            dgGridCustomer.DataSource = oCustomerList;
            dgGridCustomer.BackgroundColor = Color.Aqua;
            dgGridCustomer.ForeColor = Color.Brown;
        }
}

Scenario 2: ASP.NET page life cycle

One scenario where we see the Template pattern very much visible is in the ASP.NET page life cycle. In the ASP.NET page life cycle, the life cycle sequence is fixed but it provides full authority to override the implementation for each sequence.

For instance, in the ASP.NET page life cycle, we have various events like Init, Load, Validate, Prerender, Render, etc. The sequence is fixed, but we can override the implementation for each of these events as per our needs.

Image 4

Scenario 3: Code generators

Lots of times we generate code by using code generators like the T4 template, LINQ, EF, etc., from the database table design. Now code generators work on a separate physical file where it generates code for you. So if you change the table design, it will regenerate the file again.

Image 5

Now if you want to add some custom code, you cannot change the auto generated code file because your code will be replaced when the DB design changes. So the best approach would be to extend the code generated class using a separate file and put your custom code in that class. This extension can be done very effectively using the Template pattern. The code generated class can define a fixed process but at the same time provide empty virtual methods, properties, and functions which can be extended to be injected to your custom logic.

Scenario 4: XML parser

Another scenario which is applicable for the Template pattern is the XML parser. In XML, we normally parse the parent and child elements. In many scenarios, the parsing is almost common with minor child element changes.

For instance, in the below code snippet, we have Customer as the parent element and every customer will have Orders and Orders will have Products. Now the parsing of Customer and Orders will be the same but the Product tags can have a Size property depending on the situation. For instance, in the below code snippet, the Product element has only the name of the product and the amount.

XML
<Customer Name="Shiv">
<Orders OrderNumber="1001">
<Product Name="Shirts" Amount="1000"/>
<Product Name="Socks" Amount="100"/>
</Orders>
</Customer>

There can be situations where your Product element can have other variations as shown in the below XML snippet. In this case, you can just override the parsing process of the Product element and keep the overall XML parsing process sequence the same.

XML
<Customer Name="Shiv">
<Orders OrderNumber="1001">
<Product Name="Shirts" Amount="1000">
<LargeSize/>
</Product>
<Product Name="Socks" Amount="1000">
<SmallSize/>
</Product>
</Orders>
</Customer>

Scenario 5: Validation in business components

Business classes have validation and we would like to create different versions of business classes with different validation logic.

C#
public class Supplier
{
    private string _SupplierCode;

    public string SupplierCode
    {
        get 
        { 
            return _SupplierCode; 
        }
        set 
        {
            ValidateSuppCode(value);
            _SupplierCode = value; 
        }
    }

    public virtual  void ValidateSuppCode(string SuppCode)
    {
        if (SuppCode.Length == 0)
        {
            throw new Exception("Can not be null");
        }
    }
}

public class SupplierNew : Supplier
{
    public override void ValidateSuppCode(string SuppCode)
    {
        base.ValidateSuppCode(SuppCode);
        if (SuppCode.Length > 10)
        {
            throw new Exception("can not be more than 10");
        }
    }
}

Scenario 6: Customizable logging utility

This is one more scenario where the Template pattern fits like anything. If you look at these components, i.e., message loggers, error loggers, etc., they execute in two phases, in the first phase they prepare the message and in the second phase they log it.

For these kinds of scenarios, we can create a parent class which defines two fixed sequences: one which does the preparation of the message and the other which logs the message to the source (file, event viewer, email, etc.).

Image 6

Later we can create child classes which can inherit and override the logic of those phases but keeping the sequence intact.

Visual diagram of the Design Pattern in real time

templatepatt/Visualization.jpg

Design Pattern references

Feel free to download these FAQ PDFs, my articles on Design Patterns from my site, and I have collected around 400 FAQ questions and answers on SilverLight, Azure, VSTS, WCF, WPF, WWF, SharePoint, Design Patterns, UML, etc.

For Further reading do watch  the below interview preparation videos and step by step video series.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)