El patrón de diseño Template Method (Método Plantilla) es fundamental para definir la estructura de un algoritmo en una clase base, permitiendo que las subclases implementen pasos específicos sin alterar la lógica global. Este enfoque es especialmente útil en procesos que siguen una secuencia estricta, como la gestión de conexiones a bases de datos, donde los pasos de apertura, uso y cierre son constantes, pero el mecanismo de autenticación varía según el proveedor.
A continuación, se presenta una implementación donde una clase abstracta define el flujo de trabajo para interactuar con un motor de datos, mientras que las clases concretas resuelven la lógica de conexión específica para sistemas como Oracle o PostgreSQL.
Implementación en Java
// Clase abstracta que define el esqueleto del algoritmo
public abstract class MotorBaseDatos {
// Método que debe ser implementado por las subclases
protected abstract void establecerConexion();
// Métodos con comportamiento común
private void abrirPuerto() {
System.out.println("Puerto de comunicación abierto.");
}
private void realizarConsultas() {
System.out.println("Ejecutando sentencias SQL de usuario.");
}
private void finalizarSesion() {
System.out.println("Sesión terminada y recursos liberados.");
}
// El Método Plantilla: Orquesta la ejecución de los pasos
public final void ejecutarOperacion() {
this.establecerConexion();
this.abrirPuerto();
this.realizarConsultas();
this.finalizarSesion();
}
}
// Implementación concreta para Oracle
public class ConectorOracle extends MotorBaseDatos {
@Override
protected void establecerConexion() {
System.out.println(">>> Conectando al motor Oracle Database mediante SID...");
}
}
// Implementación concreta para PostgreSQL
public class ConectorPostgres extends MotorBaseDatos {
@Override
protected void establecerConexion() {
System.out.println(">>> Conectando a PostgreSQL mediante cadena de conexión standard...");
}
}
// Clase de prueba
public class SistemaPrincipal {
public static void main(String[] args) {
MotorBaseDatos gestor;
gestor = new ConectorOracle();
gestor.ejecutarOperacion();
System.out.println("-----------------------------------");
gestor = new ConectorPostgres();
gestor.ejecutarOperacion();
}
}
Implementación en C++
#include <iostream>
#include <memory>
using namespace std;
// Clase base que actúa como plantilla
class GestorConexiones {
public:
virtual ~GestorConexiones() {}
// Método plantilla que define la secuencia lógica
void flujoDeTrabajo() {
vincularServidor();
inicializarLogs();
procesarPeticiones();
cerrarSocket();
}
protected:
// Operación primitiva que las subclases deben definir
virtual void vincularServidor() = 0;
void inicializarLogs() {
cout << "Sistema de registro inicializado." << endl;
}
void procesarPeticiones() {
cout << "Procesando peticiones de la capa de persistencia." << endl;
}
void cerrarSocket() {
cout << "Conexión de red cerrada correctamente." << endl;
}
};
// Subclase para Oracle
class ClienteOracle : public GestorConexiones {
protected:
void vincularServidor() override {
cout << "[Oracle] Autenticando mediante esquema de usuario..." << endl;
}
};
// Subclase para SQL Server
class ClienteSQLServer : public GestorConexiones {
protected:
void vincularServidor() override {
cout << "[SQLServer] Autenticando mediante credenciales de Windows..." << endl;
}
};
int main() {
GestorConexiones* cliente = nullptr;
cliente = new ClienteOracle();
cliente->flujoDeTrabajo();
cout << "***********************************" << endl;
cliente = new ClienteSQLServer();
cliente->flujoDeTrabajo();
delete cliente;
return 0;
}
En ambos ejemplos, el beneficio principal reside en que el flujo de control (el orden de los métodos) está centralizado en la clase base. Si en el futuro se requiere añadir un paso de validación adicional para todos los motores de base de datos, solo será necesario modificar la clase abstracta, cumpliendo así con el principio de reutilización de código y mantenimiento simplificado.