Design Patterns - Template Method

Propósito

El patrón Template Method (Método Plantilla) define el esqueleto de un algoritmo, dejando algunos pasos a las subclases, que redefinen ciertos métodos sin afectar la estructura del algoritmo.

Problema

El patrón Template Method trata los siguientes problemas:

Redundancia de Código: Reduce la duplicación de código cuando múltiples clases realizan procesos similares con pequeñas diferencias.

Rigidez en la Estructura del Algoritmo: Permite variaciones en ciertas partes del algoritmo sin alterar su estructura general.

Solución

El patrón Template Method propone las siguientes soluciones:

Método Plantilla: Define un método en una clase base (la plantilla) que describe el esqueleto de un algoritmo. Este método puede incluir llamadas a otras operaciones definidas en la misma clase o en subclases.

Operaciones Concretas y Abstractas: Las operaciones usadas por el método plantilla pueden ser concretas (implementadas en la clase base) o abstractas (dejadas para implementar en las subclases).

Estructura

template method

Participantes

  • AbstractClass: Define el esqueleto del algoritmo y declara métodos abstractos que las subclases deben implementar.
  • ConcreteClass: Implementa los pasos abstractos del algoritmo definido en AbstractClass.

Cuándo Usarlo

Este patrón es recomendable cuando:

  • se tienen algoritmos con estructuras similares pero detalles diferentes, que pueden ser definidos en subclases.
  • no se quiere duplicar código, se puede centralizar el control del algoritmo.

Ventajas

Reutilización de Código: Centraliza el código común, evitando duplicarlo.

Extensibilidad: Las subclases pueden extender el algoritmo sin cambiar su estructura.

Estructura Claramente Definida: Define claramente qué partes del algoritmo son fijas y cuáles son extensibles.

Desventajas

Limitaciones en la Flexibilidad: Las subclases tienen que ajustarse a la estructura impuesta por el método plantilla.

Riesgo de Incumplir el Principio de Sustitución Liskov: Si las subclases no implementan adecuadamente los métodos abstractos, pueden incumplir la sustituibilidad.

Complejidad: Puede agregar complejidad innecesaria si solo se usa para un algoritmo simple.

Ejemplo: Sistema de Preparación de Bebidas Calientes

Debemos crear un sistema para preparar distintos tipos de bebidas calientes en una cafetería.

Cada bebida, como el té y el café, tiene un conjunto de pasos de preparación similares (como calentar el agua, combinar con el producto y servir), pero cada una también tiene sus particularidades y procesos específicos que la diferencian (como el tiempo de infusión del té o la forma de filtrar el café).

Problema

El desafío principal está en reutilizar la lógica común de preparación de bebidas, manteniendo la flexibilidad para definir y alterar los pasos específicos de cada una.

Implementar cada receta de bebida desde cero conlleva duplicación de código y hace que el sistema sea difícil de mantener y ampliar, especialmente a medida que se agregan nuevas bebidas.

Solución planteada

Elegimos el patrón Template Method porque permite definir el esqueleto del algoritmo de preparación de bebidas en una clase base, y que las subclases definan ciertos pasos del algoritmo, sin cambiar su estructura.

Encapsulamos los pasos comunes en un solo lugar e implementamos los detalles específicos de cada bebida en subclases separadas.

template method

Código Java

Codificamos en Java lo que preparamos en el diagrama.

Definimos la clase abstracta:


              
  // Paso 1: Crear la Clase Abstracta
  abstract class HotBeverageTemplate {
  
      //Métodos abstractos
      abstract void brew();
      abstract void addCondiments();
  
      // Template method
      final void prepareBeverage() {
          boilWater();
          brew();
          pourInCup();
          addCondiments();
      }
  
      void boilWater() {
          System.out.println("Hirviendo agua");
      }
  
      void pourInCup() {
          System.out.println("Vertiendo en la taza");
      }
  }
              
              

Creamos las clases concretas que definen la preparación:


              
  class Tea extends HotBeverageTemplate {
      void brew() {
          System.out.println("Infusionando el té");
      }
  
      void addCondiments() {
          System.out.println("Añadiendo limón");
      }
  }
  
  class Coffee extends HotBeverageTemplate {
      void brew() {
          System.out.println("Filtrando el café");
      }
  
      void addCondiments() {
          System.out.println("Añadiendo azúcar y leche");
      }
  }
  
              

El código cliente:


              
  public class BeverageMaker {
      public static void main(String[] args) {
          HotBeverageTemplate tea = new Tea();
          HotBeverageTemplate coffee = new Coffee();
  
          System.out.println("Preparando té:");
          tea.prepareBeverage();
  
          System.out.println("\nPreparando café:");
          coffee.prepareBeverage();
      }
  }
              
              

Mapeo (del ejemplo a Participantes)

Los participantes que vimos antes son: AbstractClass, ConcreteClass, Client:

  • HotBeverageTemplate (AbstractClass): Define los pasos del algoritmo y permite a las subclases proporcionar la implementación específica.
  • Tea, Coffee (ConcreteClass): Agrega los condimentos específicos de cada bebida.
  • BeverageMaker (Client): Usa el TemplateMethod para preparar Té y Café.

Conclusiones

El patrón Template Method resultó ideal para nuestro sistema de preparación de bebidas calientes, ofreciendo una estructura unificada y reutilizable mientras permite la personalización de los pasos específicos para cada tipo de bebida.

Se pueden integrar fácilmente nuevas bebidas sin necesidad de duplicar el código común, asegurando una solución escalable y manejable para la creciente variedad de bebidas en nuestra cafetería.

Patrones relacionados

  • Factory Method

Puede crear los objetos necesarios en el algoritmo de Template Method.

  • Strategy

Similares en que ambos definen una familia de algoritmos. Strategy permite cambiar el algoritmo completo, mientras que Template Method solo permite cambiar partes del algoritmo.