Problema
Tener algoritmos con la misma estructura pero pasos diferentes, evitando duplicar el flujo común.
Propósito
Define el esqueleto del algoritmo en la clase padre y deja que las subclases implementen los pasos específicos. El flujo general no cambia, solo los detalles.
Concepto clave
Esqueleto fijo, detalles variables: Como una receta de cocina - los pasos son siempre los mismos (preparar, cocinar, servir) pero los ingredientes y técnicas cambian según el plato.
Casos de uso comunes
- Frameworks de procesamiento de datos
- Algoritmos de ordenamiento con comparaciones personalizadas
- Pipelines de transformación
- Procesos de autenticación
- Workflows de negocio
- Algoritmos de parsing
¿Quién es quién en Template Method?
Actor | Lo que realmente es | Ejemplo | Analogía |
---|---|---|---|
AbstractClass | Define el esqueleto del algoritmo | DataProcessor - define pasos: leer, validar, transformar |
Receta de cocina (pasos fijos) |
ConcreteClass | Implementa los pasos específicos | CSVProcessor , XMLProcessor |
Cocinero específico (pasta vs pizza) |
Hook Methods | Puntos de extensión opcionales | cleanup() , postProcess() |
Pasos opcionales (“agregar especias”) |
Diagrama
classDiagram
namespace TemplateMethodPattern {
class AbstractClass {
<<abstract>>
+templateMethod()
+primitiveOperation1()*
+primitiveOperation2()*
+hook()
}
class ConcreteClassA {
+primitiveOperation1()
+primitiveOperation2()
+hook()
}
class ConcreteClassB {
+primitiveOperation1()
+primitiveOperation2()
}
}
AbstractClass <|-- ConcreteClassA
AbstractClass <|-- ConcreteClassB
Ejemplo práctico
classDiagram
namespace DataProcessorExample {
class DataProcessor {
<<abstract>>
+processData()
+readData()*
+validateData()*
+transformData()*
+saveData()*
+cleanup()
}
class CSVProcessor {
+readData()
+validateData()
+transformData()
+saveData()
}
class XMLProcessor {
+readData()
+validateData()
+transformData()
+saveData()
}
class JSONProcessor {
+readData()
+validateData()
+transformData()
+saveData()
+cleanup()
}
}
DataProcessor <|-- CSVProcessor
DataProcessor <|-- XMLProcessor
DataProcessor <|-- JSONProcessor
Flujo del algoritmo
flowchart TD
A[templateMethod] --> B[readData]
B --> C[validateData]
C --> D{validation passed?}
D -->|Yes| E[transformData]
D -->|No| F[handleValidationError]
E --> G[saveData]
F --> H[cleanup]
G --> I[hook: postProcess]
I --> H
H --> J[End]
subgraph "Abstract Methods"
B
C
E
G
end
subgraph "Hook Methods"
F
I
end
Flujo de ejecución
sequenceDiagram
participant Client
participant ConcreteClass
participant AbstractClass
Client->>ConcreteClass: processData()
ConcreteClass->>AbstractClass: templateMethod()
AbstractClass->>ConcreteClass: readData()
ConcreteClass-->>AbstractClass: data
AbstractClass->>ConcreteClass: validateData()
ConcreteClass-->>AbstractClass: validation result
alt validation passed
AbstractClass->>ConcreteClass: transformData()
ConcreteClass-->>AbstractClass: transformed data
AbstractClass->>ConcreteClass: saveData()
ConcreteClass-->>AbstractClass: save result
end
AbstractClass->>ConcreteClass: cleanup() [hook]
AbstractClass-->>Client: processing complete
Ventajas
- Reutilización: Reutiliza la estructura común del algoritmo
- Control: La clase base controla el flujo del algoritmo
- Extensibilidad: Fácil agregar nuevas variaciones
- Inversión de control: “Don’t call us, we’ll call you”
Desventajas
- Rigidez: La estructura del algoritmo está fija
- Herencia: Requiere herencia, no composición
- Complejidad: Puede ser difícil entender el flujo completo
- Liskov: Puede violar el principio de sustitución de Liskov
Cuándo usar
- Tienes algoritmos con estructura similar pero pasos diferentes
- Quieres controlar el flujo del algoritmo desde la clase base
- Necesitas evitar duplicación de código en algoritmos similares
- Quieres permitir extensiones en puntos específicos
Cuándo NO usar
- Los algoritmos son completamente diferentes
- Prefieres composición sobre herencia
- La estructura del algoritmo cambia frecuentemente
- Solo tienes una implementación del algoritmo
Diferencias con otros patrones
- vs Strategy: Template Method cambia solo algunos pasos del algoritmo, Strategy cambia todo el algoritmo