C# -  Template Method


 Neste artigo vou apresentar o padrão comportamental Gof Template Method.

Segundo a definição da Gang Of Four(GoF), o padrão Template Method define o esqueleto de um algoritmo em uma operação, adiando algumas etapas para as subclasses.

Este padrão permite que as subclasses redefinam certas etapas de um algoritmo sem alterar a estrutura do algoritmo. A chave para este padrão é colocar a lógica geral na classe pai abstrata e deixar as classes filhas definirem as especificações.

Este padrão é útil quando você tem um esqueleto de um algoritmo definido em uma classe base e uma pequena parte do algoritmo pode variar e é implementado com variação em uma subclasse, ou seja, a classe concreta.

Esse padrão é semelhante ao padrão Strategy, a principal diferença é a capacidade de alterar as partes de um algoritmo em vez de substituir um algoritmo inteiro.



O padrão Template Method permite definir a estrutura do algoritmo em uma classe base e sobrescrever procedimentos específicos nas classes derivadas:



1- Definimos a estrutura do algoritmo com os procedimentos na classe base;
2- Nas classes derivadas podemos sobrescrever procedimentos específicos que podem ser diferentes conforme a classe;
3- A classe Pai define o número e a ordem dos procedimentos individuais e pode fornecer uma implementação padrão para cada procedimento;
4- As classes derivadas podem sobrescrever qualquer procedimento que desejarem ou precisarem;

Template Method - Exemplo

Vamos entender a atuação do padrão com um exemplo mais concreto.

1- Suponha que você quer construir uma casa de concreto



Para isso você precisa seguir uma seqüência de passos como:

1- Construir a fundação
2- Levantar os pilares/colunas
3- Levantar as paredes
4- Colocar as janelas
5- Instalar o Telhado

Essa seqüência de procedimentos básicos deve ser seguida para construir a casa. Agora suponha que você precisa construir uma casa de madeira :



Você terá que seguir a mesma seqüência de procedimentos que foi adotado para construir a casa de concreto, a única diferença aqui é que ao invés de usar concreto vamos usar madeira.

Assim neste contexto podemos definir um Template Method que definirá quais são os procedimentos ou passos comuns que precisamos seguir para construir uma casa. Usando o template method poderemos construir qualquer tipo de casa.



Aqui estamos definindo um esqueleto de um algoritmo e permitimos que as etapas do algoritmo seja redefinida sem alterar a estrutura do algoritmo.

Diagrama UML

O diagrama UML do padrão Template Method segundo o Gof apresenta os seguintes participantes :

1- AbstractClass -  A classe abstrata que implementa um Template Method que define um esqueleto de um algoritmo. O Template Method invoca as operações primitivas e as operações definidas na classe Abstrata ou em outros objetos

2- ConcreteClass - Implementa as operações primitivas para realizar etapas específicas da subclasse do algoritmo (aqui podemos ter mais de uma classe concreta)

Quando podemos usar o padrão

Podemos usar o padrão Template Method nos seguintes cenários :

- Quando temos um grupo de algoritmos que consistem dos mesmos passos
- Quando temos algoritmos que diferem somente na implementação de passos específicos
- Quando queremos trocar de forma transparente algoritmos sem ter que alterar o código do cliente
- Quando queremos evitar a duplicação de código na estrutura geral do fluxo de trabalho

Vantagens do padrão

Como vantagens deste padrão temos que :

- É fácil de implementar e de entender
- É flexível pois deixa as subclasses decidir como implementar os passos do algoritmo
- Fornece uma forma compacta de implementar um grupo de algoritmos relacionados
- Fornece uma interface genérica para o algoritmo que mascara a implementação

Desvantagem

E como desvantagem podemos citar que :

Depurar e compreender a sequência de fluxo no padrão Template Method ás vezes pode ser confuso.

A manutenção da estrutura do Template Method pode ser um problema, pois as alterações em qualquer nível podem atrapalhar a implementação

Aplicação prática do padrão

Vamos considerar um reprodutor de vídeo (Video Player) que reproduz formatos diferentes de vídeos, como o formato mp4, mkv e avi.   Para suportar diferentes formatos de vídeo, será necessário usar o respectivo decodificador de vídeo.

Vamos definir a sequência de operações ou procedimentos que terão que ser realizadas para executar um vídeo.

1- Para executar um vídeo primeiro o arquivo deve ser carregado esta etapa será comum a todos os formatos de vídeos;
2- Apos ser carregado o vídeo terá que ser processado com o decodificador de vídeo adequado. (esta etapa vai variar conforme o formato do vídeo)
3- Apos o vídeo ser decodificado então o Video Player pode iniciar a execução do vídeo.(esta etapa será comum a todos os vídeos)

Com base neste cenários vamos implementar o padrão Template Method.

Implementação prática

Levando em conta este cenário vamos implementar o padrão Template Method usando uma aplicação Console .NET Core (.NET 5.0) criada no VS 2019 Community.

A seguir temos o diagrama de classes obtido a partir do VS 2019 na implementação do padrão:

Aqui fizemos o seguinte:

Criamos uma classe Abstrata - VideoPlayer  onde vamos definir o Template Method contendo as etapas e a ordem de execução e vamos fornecer uma implementação padrão para as etapas comuns.

A seguir vamos criar duas classes derivadas  VideoMP4 e VideoMKV  que irão implementar a etapa especifica para cada formato de vídeo.

A seguir temos o código usado na implementação:

1- A classe abstrata VideoPlayer

using System;

namespace TemplateMethod1
{
    public abstract class VideoPlayer
    {
        //'Template Method'
        public void ExecutarVideo()
        {
            CarregarArquivo();
            DecodeVideoFormato();
            IniciarExecucao();
        }
        //procedimento padrão
        public void CarregarArquivo()
        {
            Console.WriteLine("Arquivo de vídeo carregado...\n");
        }

        // procedimento que será sobrescrito
        public abstract void DecodeVideoFormato();

        // procedimento padrão
        public void IniciarExecucao()
        {
            Console.WriteLine("O Vídeo iniciou a execução...\n");
        }       
    }
}

2- A classe VideoMP4

   public class VideoMP4 : VideoPlayer
    {
        public override void DecodeVideoFormato()
        {
            Console.WriteLine("O Vídeo esta sendo processado com o Decoder MP4");
        }
    }
 

3- A classe VideoMKV

  public class VideoMKV : VideoPlayer
    {
        public override void DecodeVideoFormato()
        {
            Console.WriteLine("O Vídeo esta sendo processado com o Decoder MKV");
        }
    }

4- Program

using System;

namespace TemplateMethod1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("### Template Method ###");
            Console.WriteLine("Exemplo de implementação\n");
            Console.ReadLine();

            Console.WriteLine("--------- Video Player - video MP4 --------------\n");
            VideoPlayer arquivoVideo = new VideoMP4();
            arquivoVideo.CarregarArquivo();
            arquivoVideo.DecodeVideoFormato();
            arquivoVideo.IniciarExecucao();

            Console.WriteLine("----------------Video Player - vídeo MKV ---------------\n");
            arquivoVideo = new VideoMKV();
            arquivoVideo.CarregarArquivo();
            arquivoVideo.DecodeVideoFormato();
            arquivoVideo.IniciarExecucao();

            Console.ReadLine();
        }
    }
}

A execução do projeto irá apresentar o seguinte resultado:

Note que no Template Method você pode controlar o fluxo dos algoritmos. Os clientes não podem alterá-los; e outro ponto importante é que as operações comuns estarão em um local centralizado ou seja na classe abstrata.

As subclasses podem redefinir apenas as partes que variam e assim você evita a duplicação de código.

Este padrão se parece com o padrão Strategy  com as seguintes diferenças :

E para concluir podemos dizer que o Factory Method é uma especialização do Template Method.

"O homem bom, do bom tesouro do seu coração tira o bem, e o homem mau, do mau tesouro do seu coração tira o mal, porque da abundância do seu coração fala a boca."
Lucas 6:45


Referências:


José Carlos Macoratti