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:

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:

Na Guiando, buscamos entregar o melhor software no melhor tempo, com o melhor custo. Nos preocupamos em melhorar nossos processos...
Se há algo que aprendi na “escola da vida” é que sempre que temos algo importante para decidir, se não...
In this post, I will show how to do your first steps with OpenCV quickly using Visual Studio 2017 and...
Parsing large files is a recurring and challenging task. Right? It is too easy to write slow code that consumes...
Há muitos anos, tinha o hábito de fazer elogios públicos a tudo que achava que estava sendo bem-feito. Achava honestamente...
Em todos esses anos tenho recebido relatos de desenvolvedores projetando sistemas com belas arquiteturas. Muitos deles tem levantado um bocado de questões...
Masterclass

O Poder do Metamodelo para Profissionais Técnicos Avançarem

Nesta masterclass aberta ao público, vamos explorar como o Metamodelo para a Criação, desenvolvido por Elemar Júnior, pode ser uma ferramenta poderosa para alavancar sua carreira técnica em TI.

Crie sua conta

Preencha os dados para iniciar o seu cadastro no plano anual do Clube de Estudos:

Crie sua conta

Preencha os dados para iniciar o seu cadastro no plano mensal do Clube de Estudos:

× Precisa de ajuda?