Template Method Implementation in C#: An Easy Way to Make Your Code Hum Along

A pet project I’ve been working on (on and off, time permitting) has been in need of some serious refactoring, so I finally sat down to eliminate some redundancy, and work on some design pattern work. A common problem in software design is making sure base class implementation is always called from overrides, but also deferring finer grained details to subclasses without changing the base class implementation, without having to always specify base.<implementation> in every single override in subclasses. Enter, the Template Method design pattern, which encompasses the polymorphic aspect of Object Oriented Design (which in my opinion is the most important of the 3 pillars: Encapsulation, Inheritance (aka Specialization) being the other two).

The premise is simple, and here’s a very simple UML diagram that outlines the functionality:

The base class specifies stubs (abstract methods, or protected virtual method implementations that all subclasses need base functionality for), and a public method that provides the “template” that must be followed. I’ll use a simple example for the sake of brevity. Let’s say you need a Data Access Object that connects to a database and fetches some data. The members common to all derived classes would be something like connecting to the database, then providing tidy cleanup code for the disconnect. Deriving classes would need to implement their own logic for fetching and processing the data, but all derived classes need to follow the same order of operations:

  1. Connect/Authenticate
  2. Fetch
  3. Process
  4. Disconnect/Cleanup

This very simple example provides our template. So, our base class stub would look something like the following:

   1: abstract class DataAccessObject
   2:     {
   3:         protected string connectionString;
   4:         protected DataSet dataSet;
   6:         public virtual void Connect()
   7:         {
   8:             // Make sure mdb is on solution root directory
   9:             connectionString = 
  10:                 "provider=Microsoft.JET.OLEDB.4.0; " +
  11:                 "data source=..\\..\\..\\db1.mdb";
  12:         }
  14:         public abstract void Select();
  15:         public abstract void Process();
  17:         virtual public void Disconnect()
  18:         {
  19:             connectionString = "";
  20:         }
  22:         // The "Template Method" 
  24:         public void Run()
  25:         {
  26:             Connect();
  27:             Select();
  28:             Process();
  29:             Disconnect();
  30:         }
  31:     }

Now we declare subclasses that implement the stub functionality of the abstract methods, Our base class will defer the fine grained details to the derived classes, but still guarantee that the core functionality is implemented. A simple class that selects a DataSet of Products from our fictitious database could look something like the following:

   1: class Products : DataAccessObject
   2:     {
   3:         public override void Select()
   4:         {
   5:             string sql = "select ProductName from Products";
   6:             OleDbDataAdapter dataAdapter = new OleDbDataAdapter(
   7:                 sql, connectionString);
   9:             dataSet = new DataSet();
  10:             dataAdapter.Fill(dataSet, "Products");
  11:         }
  13:         public override void Process()
  14:         {
  15:             Console.WriteLine("Products ---- ");
  16:             DataTable dataTable = dataSet.Tables["Products"];
  17:             foreach (DataRow row in dataTable.Rows)
  18:             {
  19:                 Console.WriteLine(row["ProductName"]);
  20:             }
  21:             Console.WriteLine();
  22:         }
  23:     }

We could create as many subclasses as we need for various data fetching tasks, then from our main class, simply instantiate the specific subclasses and call the “Run()” method, which is a hook into our template. That would look like the following:

   1: static void Main()
   2:         {
   3:             DataAccessObject dao;
   5:             dao = new Products();
   6:             dao.Run();
   8:             // Wait for user
   9:             Console.Read();
  10:         }

The beauty of this is that we are guaranteed the template behavior from all subclasses, and it makes our code much less brittle as we know that the inheritance chain will always return the desired implementation. If you combine this with Factory Method Pattern, you can start to harness some real power of polymorphic programming. But, that’s another post.