Template Method in C#
Tags: beginners, programming, tutorial, csharp
Published: 2023-04-25 13:48:30

The Template Method design pattern is a behavioral design pattern in which a superclass defines the skeleton of an algorithm but allows subclasses to override specific algorithm steps. It can be used to create adaptable algorithms. It also prevents subclasses from making incompatible changes to the algorithm.

In this pattern, a base class defines the basic steps of an algorithm and the order in which they are executed. These stages are declared as abstract methods that must be implemented by concrete subclasses. The algorithm is designed to be extendable, so subclasses can override particular parts of the process to tailor its behavior.

The template method pattern is beneficial when you have numerous classes that implement similar algorithms but with tiny changes in the details of each algorithm. Rather than repeating the code for each algorithm, the template method pattern allows you to factor out the common code into a base class, making it easier to maintain and update.

You can find the example code of this post, on [GitHub](https://github.com/Kalkwst/DesignPatterns)

## Conceptualizing the Problem
Imagine that we're creating a data analysis application that swifts through different analytics data. Users can feed the app with endpoints from various analytics producers, and it tries to extract meaningful data from the responses of the systems in a uniform format.

The first version of the application could work only with Google Analytics. In the following version it could support Hotjar Analytics. A month later, we taught it to retrieve Sitecore Analytics also.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jqdnm7v40o0f3ph7u75o.PNG)

At some point, we saw that a lot of the code in all three classes was the same. In each class, the code for dealing with different data formats was completely different, but the code for handling and analyzing data was almost the same. Wouldn't it be great to get rid of the duplicate code without changing the way the method works?

The client code that used these classes was also a source of trouble. It had a lot of conditionals that chose the right thing to do based on the class of the object being processed. If all three processing classes shared a common interface or base class, we  could get rid of the conditionals in client code and use polymorphism when calling a processing object's functions.

The Template Method design suggests that we should break up an algorithm into a series of steps, turn these steps into methods, and put a series of calls to these methods inside a single template method. The steps may be `abstract`, or they may have some default implementation. To use the algorithm, the client should provide its own subclass, implement all abstract steps, and, if necessary, modify some of the optional steps (but not the template method itself).

Let's see how this works in our mining app. All three parsing methods can be built on the same base class. This class sets up a template method that consists of a number of calls to different steps in the document-processing process.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0fzr5vv2fxcaozm68rs7.PNG)

First, we can make all of the steps `abstract`, which means that subclasses must create their own code for these methods. In our case, subclasses already have all the appropriate implementations, so the only thing we might need to do is change the method signatures to match those of the methods in the superclass.

Now, let's see what we can do to get rid of the duplicate code. It looks like the code for opening and closing connections and extracting and parsing data is different for provider, so there's no reason to touch those methods. But the code for other steps, like processing raw data and writing reports, is very similar, so it can be **pulled up** into the base class and shared by subclasses.

There are three types of steps:
- *abstract steps*
- *optional steps*
- *hooks*

**Abstract steps**, are the steps that must be implemented by every subclass, such as opening and closing connections with a data provider.

**Optional steps**, are the steps that have some default implementation, but still can be overriden if needed. Such a step could be the processing of raw data or writing the report.

**Hooks**, are optional steps with an empty body. A template method would work even if a hook isn't changed. Most of the time, hooks are put before and after important steps in algorithms. This gives subclasses more places to add to an algorithm.

## Structuring the Template Method Pattern
In its base implementation, the Template Method has 2 participants:
- **Abstract Class**: The **Abstract Class** defines methods that act as steps in an algorithm, as well as the actual template method that calls these methods in a certain sequence. Either the steps can be labeled `abstract` or they can have a default implementation.
- **Concrete Class**: All of the steps can be changed by **Concrete Classes**, but not the template method itself.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mgwh2vo3i0ovk1l9oo1z.PNG)

To demonstrate how the Template Pattern works, we are going to create a small social media aggregator. In this example, our Template Method will define an algorithm for communicating with a social network. Subclasses that match a particular social network will implement these steps according to the specific network's API.

First we are going to define our **Template Method** participant, the `Network` class.
```csharp
namespace TemplateMethod.SocialNetworks;

public abstract class SocialNetwork
{
    protected string username;
    protected string password;

    protected SocialNetwork()
    {
    }

    /// <summary>
    /// Publish a post to a social network.
    /// </summary>
    /// <param name="message">The message to post.</param>
    /// <returns>true if the message is successfully posted, false otherwise.</returns>
    public bool Post(string message)
    {
        if (!LogIn(username, password)) 
            return false;
        
        var result = SendData(Encoding.ASCII.GetBytes(message));
        LogOut();
        return result;

    }

    protected abstract bool LogIn(string username, string password);
    protected abstract bool SendData(byte[] data);
    protected abstract void LogOut();
}
```

We first need to define an *abstract* `SocialNetwork` class, which will provide our framework for publishing posts to social networks. We will also define two `protected` members, `username` and `password` to use for the login process.

The `Post` method is defined as public and takes a string parameter `message` as input. This method is implemented in our **Template Method** class, since the posting mechanism is the same across all social networks. This method performs a login workflow, and if successful it sends the data to the social network and then logs out. Note that while the class implements the `Post` method, the specifics for the login, posting and logout are left for the concrete classes.

The `LogIn`, `SendData` and `Logout` methods are all marked as `abstract` meaning that they are not implemented in the `SocialNetwork` class and must be implemented by its derived classes. This way, derived classes can define their own workflows and logic depending on the API provided by each social network.

Now let's implement our concrete classes. First is the `Facebook` class:
```csharp
public class Facebook : SocialNetwork
{
    public Facebook(string username, string password)
    {
        base.username = username;
        base.password = password;
    }

    protected override bool LogIn(string username, string password)
    {
        Console.WriteLine("\nChecking user's credentials");
        Console.WriteLine($"Name: {username}");
        Console.Write("Password: ");
        
        for(var i = 0; i < password.Length; i++)
            Console.Write("*");

        SimulateLatency();
        Console.WriteLine("\n\nFacebook login successful");
        return true;
    }

    protected override bool SendData(byte[] data)
    {
        Console.WriteLine($"Message was posted successfully on Facebook");
        return true;
    }

    protected override void LogOut()
    {
        Console.WriteLine($"User '{username}' was logged out from Facebook");
    }

    private void SimulateLatency()
    {
        var i = 0;
        var end = new Random().Next(5, 15);
        
        Console.WriteLine();
        while (i < end)
        {
            Console.Write(".");
            Thread.Sleep(new Random().Next(200, 800));
            i++;
        }
    }
}
```

The `Facebook` class implements all of the abstract methods defined by the `SocialNetwork`. Note that while it can call the parent class's `Post` method, it will use its own implementations of `Login`, `Logout` and `SendData`.

Same goes for the `Twitter` class:
```csharp
namespace TemplateMethod.SocialNetworks;

public class Twitter : SocialNetwork
{
    public Twitter(string username, string password)
    {
        base.username = username;
        base.password = password;
    }

    protected override bool LogIn(string username, string password)
    {
        Console.WriteLine("\nChecking user's credentials");
        Console.WriteLine($"Name: {username}");
        Console.Write("Password: ");
        
        for(var i = 0; i < password.Length; i++)
            Console.Write("*");

        SimulateLatency();
        Console.WriteLine("\n\nTwitter login successful");
        return true;
    }

    protected override bool SendData(byte[] data)
    {
        Console.WriteLine($"Message was posted successfully on Twitter");
        return true;
    }

    protected override void LogOut()
    {
        Console.WriteLine($"User '{username}' was logged out from Twitter");
    }

    private void SimulateLatency()
    {
        var i = 0;
        var end = new Random().Next(5, 15);
        
        Console.WriteLine();
        while (i < end)
        {
            Console.Write(".");
            Thread.Sleep(new Random().Next(200, 800));
            i++;
        }
    }
}
```

And finally the `DevTo` class:
```csharp
namespace TemplateMethod.SocialNetworks;

public class DevTo : SocialNetwork
{
    public DevTo(string username, string password)
    {
        base.username = username;
        base.password = password;
    }

    protected override bool LogIn(string username, string password)
    {
        Console.WriteLine("\nChecking user's credentials");
        Console.WriteLine($"Name: {username}");
        Console.Write("Password: ");
        
        for(var i = 0; i < password.Length; i++)
            Console.Write("*");

        SimulateLatency();
        Console.WriteLine("\n\nDevTo login successful");
        return true;
    }

    protected override bool SendData(byte[] data)
    {
        Console.WriteLine($"Message was posted successfully on DevTo");
        return true;
    }

    protected override void LogOut()
    {
        Console.WriteLine($"User '{username}' was logged out from DevTo");
    }

    private void SimulateLatency()
    {
        var i = 0;
        var end = new Random().Next(5, 15);
        
        Console.WriteLine();
        while (i < end)
        {
            Console.Write(".");
            Thread.Sleep(new Random().Next(200, 800));
            i++;
        }
    }
}
```

Now that we have our **ConcreteClass** participants, we are going to create our main class and run our program:
```csharp
using TemplateMethod.SocialNetworks;

SocialNetwork network = null;

Console.Write("Enter your username: ");
var username = Console.ReadLine();
Console.Write("Enter your password: ");
var password = Console.ReadLine();
Console.Write("Enter your post message: ");
var message = Console.ReadLine();

Console.WriteLine(@"Choose the social network you want to post to:
                        1. Facebook\n
                        2. Twitter\n
                        3. Dev.to");
var choice = int.Parse(Console.ReadLine());

network = choice switch
{
    1 => new Facebook(username, password),
    2 => new Twitter(username, password),
    3 => new DevTo(username, password),
    _ => throw new Exception()
};

network.Post(message);
```

The program first prompts the user to enter their username, password, and message to post. Then, it displays a menu with three social networks to choose from: *Facebook*, *Twitter*, and *Dev.to*. The user's choice is read from the console input using the `int.Parse` method, which converts the user's input from a string to an integer.

Next, a new instance of the `SocialNetwork` class is created based on the user's choice using a switch statement. Depending on the user's input, the `network` variable is set to a new instance of either the `Facebook`, `Twitter`, or `DevTo` class, passing in the `username` and `password` entered by the user.

Now remember that each of the concrete classes extend the **SocialNetwork** class, so they all have the `Post` method available. The only thing changing is how the `Post` method's algorithm handles the different network APIs. Depending on the network selected, the `Post` method will call the appropriate implementations of `Login`, `SendData` and `Logout`.

Now the output of the above would be something like:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7u7vjfotll4n2maolrba.PNG)

## Pros and Cons of the Template Method Pattern
|||
|:--|:--|
|✔ By allowing clients to override only specific portions of a complex algorithm, it is possible to minimize the impact of changes made to other parts of the algorithm on those clients.|❌The provided framework of an algorithm may constrain certain clients.|
|✔The repeated code can be consolidated into a superclass.|❌A default step implementation in a superclass could be suppressed by a subclass, resulting in a violation of the *Liskov Substitution Principle*.|
||❌ As the number of steps in a template method increases, the difficulty of maintaining it also tends to increase.|

## Relations with Other Patterns
- The **Factory Method** design pattern is a specialized form of the **Template Method** design pattern. However, a **Factory Method** can also function as a step in a larger **Template Method**.
- The **Template Method** design pattern relies on inheritance to allow subclasses to modify specific parts of an algorithm. In contrast, the **Strategy** pattern relies on composition to alter an object's behavior by providing it with different strategies. The **Template Method** is implemented at the class level and is static, meaning its structure is determined at compile-time. On the other hand, the **Strategy** pattern operates on the object level, allowing for dynamic switching of behaviors at runtime.

## Final Thoughts
In this article, we have discussed what is the Template Method pattern, when to use it and what are the pros and cons of using this design pattern. We then examined some use cases for this pattern and how the Template Method relates to other classic design patterns. 

It's worth noting that the Template Method pattern, along with the rest of the design patterns presented by the Gang of Four, is not a panacea or a be-all-end-all solution when designing an application. Once again it's up to the engineers to consider when to use a specific pattern. After all these patterns are useful when used as a precision tool, not a sledgehammer.