C# Template Method Pattern

Summary: in this tutorial, you’ll learn about the Template Method pattern and how to implement it in C#.

Introduction to the C# Template Method Pattern

The Template Method pattern defines a skeleton of an algorithm in a superclass and allows subclasses to redefine specific steps of the algorithm without changing its structure.

The following UML diagram illustrates the Template Method pattern:

C# Template Method Pattern

Typically, the Template Method consists of an abstract class that defines the structure of the algorithm and concrete subclasses that implement the specific steps of the algorithm.

The abstract class provides a set of template methods that the subclasses can override to provide their own implementation.

In practice, you use the Template Method pattern when you have an algorithm that you need to implement in a similar way across multiple classes but with some slight variations.

Instead of duplicating the same code across different classes, you can define a standard template in a superclass, and then override some methods in the subclasses to customize the corresponding algorithm steps.

The Template Method pattern reduces code duplication, increases code reuse, and makes it easier to maintain and modify the algorithm in the future.

C# Template Method pattern example

The following program demonstrates how to use the Template Method pattern to define a generic algorithm for reading data from a file, transforming it, and storing it in a database while allowing subclasses to override specific steps to handle different file formats and database types:

namespace TemplateMethodPattern;


// Abstract class that defines the template method
// and its steps
public abstract class ETL
{
    public void ImportData(string filename)
    {
        // Step 1: read data from file
        var data = Extract(filename);

        // Step 2: transform data
        var transformedData = Transform(data);

        // Step 3: store data in database
        Load(transformedData);
    }

    protected abstract string[] Extract(string filename);

    protected virtual string[] Transform(string[] data)
    {
        // Default implementation of transformation
        // that does nothing
        return data;
    }

    protected abstract void Load(string[] data);
}

// Concrete subclass that handles
// CSV files and SQL Server database
public class CSVToSQLServer : ETL
{
    protected override string[] Extract(string filename)
    {
        // Read CSV file and return data as an array of strings
        return File.ReadAllLines(filename);
    }

    protected override void Load(string[] data)
    {
        // Store data in SQL Server database
        // Implementation omitted for brevity
        Console.WriteLine("Store Data in SQL Server");
    }
}

// Concrete subclass that handles
// Excel files and MySQL database
public class ExcelToMySQL : ETL
{
    protected override string[] Extract(string filename)
    {
        // Read Excel file and return data as an array of strings
        // Implementation omitted for brevity
        return new string[] { "1,2,3", "4,5,6" };
    }

    protected override string[] Transform(string[] data)
    {
        // Transform Excel data to CSV format
        // Implementation omitted for brevity
        Console.WriteLine("Excel data transformed to CSV format");
        return data;
    }

    protected override void Load(string[] data)
    {
        // Store data in MySQL database
        // Implementation omitted for brevity
        Console.WriteLine("Data stored in MySQL");
    }
}

public class Program
{
    static void Main(string[] args)
    {
        // Import CSV data into SQL Server
        var csvSqlServerImport = new CSVToSQLServer();
        csvSqlServerImport.ImportData("data.csv");

        // Import Excel data into MySQL
        var excelMySqlImport = new ExcelToMySQL();
        excelMySqlImport.ImportData("data.xlsx");

    }
}Code language: C# (cs)

How it works.

First, define an abstract class called ETL (Extract, Transform, Load) that contains the template method called ImportData.

The ImportData method defines the steps to import data from a file, transform the data, and load it into a database.

The ImportData method calls three abstract methods, Extract, Transform, and Load, which represent the specific steps of the ETL process:

  • The Extract method is responsible for reading data from a file.
  • The Transform method transforms the data.
  • The Load method saves the transformed data in a database.

We mark the Extract and Load methods as abstract so that the subclasses need to implement them. We also mark the Transform method as virtual and provide a default implementation. The subclasses can override the Transform method if necessary:

// Abstract class that defines the template method
// and its steps
public abstract class ETL
{
    public void ImportData(string filename)
    {
        // Step 1: read data from file
        var data = Extract(filename);

        // Step 2: transform data
        var transformedData = Transform(data);

        // Step 3: store data in database
        Load(transformedData);
    }

    protected abstract string[] Extract(string filename);

    protected virtual string[] Transform(string[] data)
    {
        // Default implementation of transformation
        // that does nothing
        return data;
    }

    protected abstract void Load(string[] data);
}Code language: C# (cs)

Second, define the CSVToSQLServer class that inherits from the ETL class. The CSVToSQLServer implements the Extract() method to read data from a CSV file and the Load() method to store the data in a SQL Server database:

// Concrete subclass that handles
// CSV files and SQL Server database
public class CSVToSQLServer : ETL
{
    protected override string[] Extract(string filename)
    {
        // Read CSV file and return data as an array of strings
        return File.ReadAllLines(filename);
    }

    protected override void Load(string[] data)
    {
        // Store data in SQL Server database
        // Implementation omitted for brevity
        Console.WriteLine("Store Data in SQL Server");
    }
}Code language: C# (cs)

Third, define the ExcelToMySQL class that extends the ETL class. The CSVToSQLServer class implements the Extract() method to read data from an Excel file and the Load() method to store the data in a MySQL Server database:

// Concrete subclass that handles
// Excel files and MySQL database
public class ExcelToMySQL : ETL
{
    protected override string[] Extract(string filename)
    {
        // Read Excel file and return data as an array of strings
        // Implementation omitted for brevity
        return new string[] { "1,2,3", "4,5,6" };
    }

    protected override string[] Transform(string[] data)
    {
        // Transform Excel data to CSV format
        // Implementation omitted for brevity
        Console.WriteLine("Excel data transformed to CSV format");
        return data;
    }

    protected override void Load(string[] data)
    {
        // Store data in MySQL database
        // Implementation omitted for brevity
        Console.WriteLine("Data stored in MySQL");
    }
}Code language: C# (cs)

Finally, the Main() method of the program uses the CSVToSQLServer and ExcelToMySQL classes to import data from CSV and Excel files and save the data to a SQL Server and MySQL, respectively.

public class Program
{
    static void Main(string[] args)
    {
        // Import CSV data into SQL Server
        var csvSqlServerImport = new CSVToSQLServer();
        csvSqlServerImport.ImportData("data.csv");

        // Import Excel data into MySQL
        var excelMySqlImport = new ExcelToMySQL();
        excelMySqlImport.ImportData("data.xlsx");
    }
}Code language: C# (cs)

Summary

  • Use the Template Method pattern to define the skeleton of an algorithm in a superclass and allow subclasses to override specific steps of the algorithm without changing its structure.
Was this tutorial helpful ?