Introducción a los patrones de diseño en C++
Los patrones de diseño (design patterns) son soluciones arquitectónicas probadas por el tiempo para problemas típicos de desarrollo. En el mundo de C++ son especialmente importantes, ya que permiten crear código flexible, extensible y mantenible. En este artículo analizaremos cuatro patrones fundamentales: Singleton, Factory Method, Observer y Strategy — con ejemplos completos en C++ moderno (C++17/20).
Cada patrón estará acompañado de un ejemplo práctico, un diagrama de clases y explicaciones sobre su aplicación. El material está dirigido a desarrolladores que ya conocen los fundamentos de C++ y POO.
1. Patrón creacional Singleton (Instancia única)
Singleton garantiza que una clase tiene solo una instancia y proporciona un punto de acceso global a ella. En C++, la implementación clásica utiliza un método estático y un constructor privado.
Cuándo aplicarlo
- Gestión de la conexión con la base de datos
- Sistema de logging
- Gestor de caché
- Configuración de la aplicación
Ejemplo de implementación (Singleton thread-safe)
#include <iostream>#include <mutex>#include <memory>
class Logger {private: static std::unique_ptr<Logger> instance; static std::mutex mtx; Logger() { std::cout << "Logger creado" << std::endl; } public: Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete; static Logger* getInstance() { std::lock_guard<std::mutex> lock(mtx); if (!instance) { instance.reset(new Logger()); } return instance.get(); } void log(const std::string& msg) { std::cout << "[LOG] " << msg << std::endl; }};
std::unique_ptr<Logger> Logger::instance = nullptr;std::mutex Logger::mtx;
int main() { Logger* log1 = Logger::getInstance(); Logger* log2 = Logger::getInstance(); log1->log("Mensaje de prueba"); // log1 y log2 apuntan al mismo objeto std::cout << "log1 == log2: " << (log1 == log2) << std::endl; return 0;}Enfoque moderno de C++ (Meyers' Singleton)
class ConfigManager {public: static ConfigManager& getInstance() { static ConfigManager instance; // thread-safe en C++11+ return instance; } void setParam(const std::string& key, const std::string& value) { params[key] = value; } std::string getParam(const std::string& key) { return params[key]; } private: ConfigManager() = default; std::map<std::string, std::string> params;};2. Patrón creacional Factory Method (Método de fábrica)
Factory Method define una interfaz para crear un objeto, pero permite que las subclases elijan la clase concreta del objeto a crear. Este patrón es especialmente útil cuando el tipo de objeto no se conoce de antemano.
Estructura del patrón
- Product — clase abstracta del producto
- ConcreteProduct — implementación concreta del producto
- Creator — clase abstracta del creador con el método de fábrica
- ConcreteCreator — redefine el método de fábrica
Ejemplo: sistema de notificaciones
#include <iostream>#include <memory>#include <string>
// Producto abstractoclass Notification {public: virtual void send(const std::string& message) = 0; virtual ~Notification() = default;};
// Productos concretosclass EmailNotification : public Notification {public: void send(const std::str
```