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
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.
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:
- Create the template or the main process by creating a parent abstract class.
- Create the sub-processes by defining abstract methods and functions.
- 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.
- Finally create the child classes which can alter the abstract methods or sub-process to define a new implementation.
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.
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.
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.
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.
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.
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.
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:
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.
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.
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 Product
s. 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.
<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.
<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.
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.).
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
Design Pattern references
- Part 1 Design pattern FAQ's -- Factory pattern, Abstract Factory pattern, Builder pattern, Prototype pattern, Singleton pattern, and Command pattern
- Part 2 Design Pattern FAQ's -- Interpreter pattern, Iterator pattern, Mediator pattern, Memento pattern, and Observer pattern
- Part 3 Design Pattern FAQ's -- State pattern, Strategy pattern, Visitor pattern, Adapter pattern, and Fly weight pattern
- Part 4 Design Pattern FAQ's -- Bridge Pattern, Composite Pattern, Decorator Pattern, Facade Pattern, Chain of Responsibility (COR), Proxy pattern, and Template pattern
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.