Template Method pattern in C#

Hi there, C# lovers! 😍

Today I want to talk to you about one of my favorite design patterns: the Template Method pattern. ðŸŽĻ

The Template Method pattern is a behavioral pattern that defines the skeleton of an algorithm in a base class but lets subclasses override some steps of the algorithm without changing its structure. ðŸĶī

This way, you can reuse the common logic in the base class, and customize the specific behavior in the subclasses. 🙌

Sounds abstract? Don’t worry, I’ll show you a concrete example in C#. 😉

Let’s say you have an online store that processes orders using different payment methods: credit card, PayPal, or cash on delivery. ðŸ’ģ ðŸ’ļ 💰

You want to have a consistent way of processing orders, but each payment method may have some variations. For example, credit card orders need to validate the card number and charge the amount, PayPal orders need to redirect to the PayPal website and confirm the payment, and cash-on-delivery orders need to print a receipt and collect the money when delivering the product. 📝

How can you implement this scenario using the Template Method pattern? Easy peasy! 😎

First, you create an abstract base class that defines the steps of processing an order. You can make some steps abstract and let the subclasses implement them, and some steps concrete and provide a default implementation. 

For example:


// The abstract base class that defines the template method and common steps
public abstract class OrderProcessor
{
    // The template method that calls the steps in order
    public void ProcessOrder()
    {
        ValidateOrder();
        PrepareProduct();
        ProcessPayment();
        DeliverProduct();
    }

    // A common step that is the same for all subclasses
    protected void ValidateOrder()
    {
        Console.WriteLine("Validating order...");
    }

    // A common step that is the same for all subclasses
    protected void PrepareProduct()
    {
        Console.WriteLine("Preparing product...");
    }

    // An abstract step that subclasses must implement
    protected abstract void ProcessPayment();

    // An abstract step that subclasses must implement
    protected abstract void DeliverProduct();
}

Next, you create concrete subclasses that inherit from the base class and override the abstract steps according to their payment method. 

For example:


// A concrete subclass that implements credit card payment
public class CreditCardOrder : OrderProcessor
{
    // Override the abstract step to process credit card payment
    protected override void ProcessPayment()
    {
        Console.WriteLine("Validating card number...");
        Console.WriteLine("Charging amount...");
    }

    // Override the abstract step to deliver product by courier
    protected override void DeliverProduct()
    {
        Console.WriteLine("Delivering product by courier...");
    }
}

// A concrete subclass that implements PayPal payment
public class PayPalOrder : OrderProcessor
{
    // Override the abstract step to process PayPal payment
    protected override void ProcessPayment()
    {
        Console.WriteLine("Redirecting to PayPal website...");
        Console.WriteLine("Confirming payment...");
    }

    // Override the abstract step to deliver product by email
    protected override void DeliverProduct()
    {
        Console.WriteLine("Delivering product by email...");
    }
}

// A concrete subclass that implements cash on delivery payment
public class CashOnDeliveryOrder : OrderProcessor
{
    // Override the abstract step to process cash on delivery payment
    protected override void ProcessPayment()
    {
        Console.WriteLine("Printing receipt...");
        Console.WriteLine("Collecting money...");
    }

    // Override the abstract step to deliver product by hand
    protected override void DeliverProduct()
    {
        Console.WriteLine("Delivering product by hand...");
    }
}


Finally, you can use any subclass to process an order using its specific payment method. 

For example:


// Create a credit card order and process it
OrderProcessor creditCardOrder = new CreditCardOrder();
creditCardOrder.ProcessOrder();

// Output:
// Validating order...
// Preparing product...
// Validating card number...
// Charging amount...
// Delivering product by courier...

// Create a PayPal order and process it
OrderProcessor payPalOrder = new PayPalOrder();
payPalOrder.ProcessOrder();

// Output:
// Validating order...
// Preparing product...
// Redirecting to PayPal website...
// Confirming payment...
// Delivering product by email...

// Create a cash on delivery order and process it
OrderProcessor cashOnDeliveryOrder = new CashOnDeliveryOrder();
cashOnDeliveryOrder.ProcessOrder();

// Output:
// Validating order...
// Preparing product...
// Printing receipt...
// Collecting money...
// Delivering product by hand...

And that’s it! You have successfully implemented the Template Method pattern in C#. 🎉

As you can see, this pattern is very useful when you have a common algorithm with some variable steps. You can avoid code duplication and increase flexibility by delegating the details to subclasses. 👍


If you want to learn more about this pattern, check out these awesome resources:


I hope you enjoyed this article and learned something new. If you did, please share it with your friends and leave a comment below. 😊

You can find the code examples here: source code


Stay tuned for more C# tips and tricks! Happy coding! 😁

Comments

Popular posts from this blog

Which GOF patterns are good for C#?

Angular on a regular SharePoint page (part 2)

Chain of Responsibility pattern in C#