.NET Design Patterns

Template Method


 Definition
 UML diagram
 Participants
 Structural code in C#
 Real-world code in C#
 .NET Optimized code in C#



Definition

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

Frequency of use:
Medium




UML class diagram






Participants


    The classes and objects participating in this pattern are:

  • AbstractClass  (DataObject)
    • defines abstract primitive operations that concrete subclasses define to implement steps of an algorithm
    • implements a template method defining the skeleton of an algorithm. The template method calls primitive operations as well as operations defined in AbstractClass or those of other objects.
  • ConcreteClass  (CustomerDataObject)
    • implements the primitive operations ot carry out subclass-specific steps of the algorithm



Structural code in C#


This structural code demonstrates the Template method which provides a skeleton calling sequence of methods. One or more steps can be deferred to subclasses which implement these steps without changing the overall calling sequence.

                 

using System;

 

namespace DoFactory.GangOfFour.Template.Structural

{

  /// <summary>

  /// MainApp startup class for Real-World

  /// Template Design Pattern.

  /// </summary>

  class MainApp

  {

    /// <summary>

    /// Entry point into console application.

    /// </summary>

    static void Main()

    {

      AbstractClass aA = new ConcreteClassA();

      aA.TemplateMethod();

 

      AbstractClass aB = new ConcreteClassB();

      aB.TemplateMethod();

 

      // Wait for user

      Console.ReadKey();

    }

  }

 

  /// <summary>

  /// The 'AbstractClass' abstract class

  /// </summary>

  abstract class AbstractClass

  {

    public abstract void PrimitiveOperation1();

    public abstract void PrimitiveOperation2();

 

    // The "Template method"

    public void TemplateMethod()

    {

      PrimitiveOperation1();

      PrimitiveOperation2();

      Console.WriteLine("");

    }

  }

 

  /// <summary>

  /// A 'ConcreteClass' class

  /// </summary>

  class ConcreteClassA : AbstractClass

  {

    public override void PrimitiveOperation1()

    {

      Console.WriteLine("ConcreteClassA.PrimitiveOperation1()");

    }

    public override void PrimitiveOperation2()

    {

      Console.WriteLine("ConcreteClassA.PrimitiveOperation2()");

    }

  }

 

  /// <summary>

  /// A 'ConcreteClass' class

  /// </summary>

  class ConcreteClassB : AbstractClass

  {

    public override void PrimitiveOperation1()

    {

      Console.WriteLine("ConcreteClassB.PrimitiveOperation1()");

    }

    public override void PrimitiveOperation2()

    {

      Console.WriteLine("ConcreteClassB.PrimitiveOperation2()");

    }

  }

}


Output
ConcreteClassA.PrimitiveOperation1()
ConcreteClassA.PrimitiveOperation2()




Real-world code in C#


This real-world code demonstrates a Template method named Run() which provides a skeleton calling sequence of methods. Implementation of these steps are deferred to the CustomerDataObject subclass which implements the Connect, Select, Process, and Disconnect methods.

                 

using System;

using System.Data;

using System.Data.OleDb;

 

namespace DoFactory.GangOfFour.Template.RealWorld

{

  /// <summary>

  /// MainApp startup class for Real-World

  /// Template Design Pattern.

  /// </summary>

  class MainApp

  {

    /// <summary>

    /// Entry point into console application.

    /// </summary>

    static void Main()

    {

      DataAccessObject daoCategories = new Categories();

      daoCategories.Run();

 

      DataAccessObject daoProducts = new Products();

      daoProducts.Run();

 

      // Wait for user

      Console.ReadKey();

    }

  }

 

  /// <summary>

  /// The 'AbstractClass' abstract class

  /// </summary>

  abstract class DataAccessObject

  {

    protected string connectionString;

    protected DataSet dataSet;

 

    public virtual void Connect()

    {

      // Make sure mdb is available to app

      connectionString =

        "provider=Microsoft.JET.OLEDB.4.0; " +

        "data source=..\\..\\..\\db1.mdb";

    }

 

    public abstract void Select();

    public abstract void Process();

 

    public virtual void Disconnect()

    {

      connectionString = "";

    }

 

    // The 'Template Method'

    public void Run()

    {

      Connect();

      Select();

      Process();

      Disconnect();

    }

  }

 

  /// <summary>

  /// A 'ConcreteClass' class

  /// </summary>

  class Categories : DataAccessObject

  {

    public override void Select()

    {

      string sql = "select CategoryName from Categories";

      OleDbDataAdapter dataAdapter = new OleDbDataAdapter(

        sql, connectionString);

 

      dataSet = new DataSet();

      dataAdapter.Fill(dataSet, "Categories");

    }

 

    public override void Process()

    {

      Console.WriteLine("Categories ---- ");

 

      DataTable dataTable = dataSet.Tables["Categories"];

      foreach (DataRow row in dataTable.Rows)

      {

        Console.WriteLine(row["CategoryName"]);

      }

      Console.WriteLine();

    }

  }

 

  /// <summary>

  /// A 'ConcreteClass' class

  /// </summary>

  class Products : DataAccessObject

  {

    public override void Select()

    {

      string sql = "select ProductName from Products";

      OleDbDataAdapter dataAdapter = new OleDbDataAdapter(

        sql, connectionString);

 

      dataSet = new DataSet();

      dataAdapter.Fill(dataSet, "Products");

    }

 

    public override void Process()

    {

      Console.WriteLine("Products ---- ");

      DataTable dataTable = dataSet.Tables["Products"];

      foreach (DataRow row in dataTable.Rows)

      {

        Console.WriteLine(row["ProductName"]);

      }

      Console.WriteLine();

    }

  }

}


Output
Categories ----
Beverages
Condiments
Confections
Dairy Products
Grains/Cereals
Meat/Poultry
Produce
Seafood

Products ----
Chai
Chang
Aniseed Syrup
Chef Anton's Cajun Seasoning
Chef Anton's Gumbo Mix
Grandma's Boysenberry Spread
Uncle Bob's Organic Dried Pears
Northwoods Cranberry Sauce
Mishi Kobe Niku




.NET Optimized code in C#


The .NET optimized code demonstrates the same real-world situation as above but uses modern, built-in .NET features, such as, generics, reflection, object initializers, automatic properties, etc. You can find an example on our Singleton pattern page.

All other patterns (and much more) are available in our .NET Design Pattern Framework 4.5.


Not only does the .NET Design Pattern Framework 4.5 cover GOF and Enterprise patterns, it also includes .NET pattern architectures that reduce the code you need to write by up to 75%. This unique package will change your .NET lifestyle -- for only $79.  Here's what is included:



  • 69 gang-of-four pattern projects
  • 46 head-first pattern projects
  • Fowler's enterprise patterns
  • Multi-tier patterns
  • Convention over configuration
  • Active Record and CQRS patterns
  • Repository and Unit-of-Work patterns
  • MVC, MVP, & MVVM patterns
  • REST patterns with Web API
  • SparkTM Rapid App Dev (RAD) platform!
  • Art Shop MVC Reference Application
  • 100% pure source code