From GoF to Lambdas – The Strategy Pattern

In the previous post, I mentioned Mario Fusco who wrote a blog post series questioning the way Java developers are implementing the Gang of Four (GoF) patterns.

I am trying to provide a C# version of Mario’s recommendations expanding some examples. In this post, I would like to talk about the Strategy Pattern.

The Strategy Pattern

The goal of this pattern is to define a family of algorithms, encapsulate each one, and make them interchangeable. The algorithm varies independently from clients that use it.

There are three primary participants in this pattern:

  1. The strategy interface, which declares an interface common to all supported algorithms.
  2. The strategy concrete implementation, which implements the algorithm according to the strategy interface.
  3. The execution context, which is configured with a specific implementation and to define an interface that lets the strategy access its data.

How it is commonly adopted today

The first step is putting an abstract definition of the behaviors (algorithms) we want to support into an interface. Let’s assume we need to provide different sorting algorithms. So, the first step would be to define a standard interface with a sort method:

public interface IArraySortStrategy
{
    T[] Sort<T>(T[] input, Comparison<T> comparison);
}

Then, we would need to write concrete implementations of the sorting Strategy:

public class QuickSortStrategy : IArraySortStrategy
{
    public T[] Sort<T>(T[] input, Comparison<T> comparison)
    {
        // ..
    }
}

public class MergeSortStrategy : IArraySortStrategy
{
    public T[] Sort<T>(T[] input, Comparison<T> comparison)
    {
        // ..
    }
}

public class BubbleSortStrategy : IArraySortStrategy
{
    public T[] Sort<T>(T[] input, Comparison<T> comparison)
    {
        // ..
    }
}

After that, we would be ready to use it.

namespace HelloStrategy.Controllers
{
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        private readonly IArraySortStrategy _sortingStrategy;
        
        public ValuesController(IArraySortStrategy sortingStrategy)
        {
            _sortingStrategy = sortingStrategy;
        }
        // ..
    }
}

Mario’s recommendation

The strategy implementation using interfaces is too verbose. Don’t you think? We are defining classes just to wrap functions.

Let’s use a delegate instead of an interface:

public delegate T[] SortingAlgorithm<T>(T[] input, Comparison<T> comparison);

Now, we can write concrete implementations as simple functions:

public static class SortingImplementations
{
    public static T[] QuickSort<T>(T[] input, Comparison<T> comparison) {  /* .. */ }
    public static T[] MergeSort<T>(T[] input, Comparison<T> comparison) {  /* .. */ }
    public static T[] BubbleSort<T>(T[] input, Comparison<T> comparison) {  /* .. */ }
}

This is an apparently less coupled solution. We do not have to reference the strategy interface in the concrete implementation. So, we could provide concrete implementations in different assemblies with no dependencies.

In the context, we just need to specify the delegate we need instead of the interface.

namespace HelloStrategy.Controllers
{
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        private readonly SortingAlgorithm<Customer> _sortingAlgorithm;

        public ValuesController(SortingAlgorithm<Customer> sortingAlgorithm)
        {
            _sortingAlgorithm = sortingAlgorithm;
        }

        // ..
    }
}

The dependency injection container provided by ASP.net core supports it:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton>(SortingImplementations.QuickSort);
    // Add framework services.
    services.AddMvc();
}

That’s it. Next time, we will talk about the Template pattern.

Compartilhe este insight:

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Mais insights para o seu negócio

Veja mais alguns estudos e reflexões que podem gerar alguns insights para o seu negócio:

Mais uma vez, tive o prazer de compartilhar bons momentos com o pessoal do Canal.NET discutindo sobre arquitetura e tecnologia....
Um dos benefícios mais bacanas do programa MVP é o direito a participação no MVP Global Summit – evento anual,...
Retomar em plenitude todas as atividades econômicas, aumentando o risco de contágio pelo novo coronavírus e, eventualmente, sacrificar uma parcela...
Implementing synchronization for multiple threads in .NET is easy. There are a lot of options for doing that – for...
When designing systems that need to scale you always need to remember that using better resources could help you to...
Compete ao arquiteto corporativo a responsabilidade de descrever, analisar e comunicar os diversos aspectos da arquitetura corporativa, bem como registrar...
× Precisa de ajuda?