Imagen destacada del tutorial: Patrones de Diseño - Aplicaciones Avanzadas
Patrones de Diseño

Patrones de Diseño - Aplicaciones Avanzadas

José Elías Romero Guanipa
05 Sep 2025

Aprende aplicaciones avanzadas de patrones de diseño en arquitecturas empresariales como microservicios, CQRS, event sourcing y más con ejemplos prácticos en C++.

patrones diseño patrones avanzados microservicios cqrs event sourcing +5 más

¡Domina las aplicaciones avanzadas de patrones de diseño! En este tutorial especializado te guiaré paso a paso para que aprendas cómo aplicar patrones en arquitecturas empresariales modernas, incluyendo microservicios, CQRS, event sourcing, circuit breaker y API gateway, con ejemplos prácticos y casos de uso reales en C++.

Objetivo: Aprender aplicaciones avanzadas de patrones de diseño en arquitecturas empresariales, sus implementaciones en C++, ventajas, desventajas y cuándo aplicarlos en proyectos de gran escala.

¿Por qué C++ para patrones avanzados?

C++ es una excelente elección para implementar patrones de diseño avanzados en aplicaciones empresariales por varias razones fundamentales:

Rendimiento y Control de Recursos

  • Gestión de memoria precisa: Control total sobre la creación y destrucción de objetos
  • Bajo overhead: Sin garbage collector, ideal para sistemas de alta performance
  • Multi-threading nativo: Soporte robusto para concurrencia con std::thread y async/await

Escalabilidad y Robustez

  • Compilación estricta: Errores detectados en tiempo de compilación
  • Abstracciones de bajo nivel: Control sobre optimizaciones del compilador
  • Estabilidad: Código que funciona consistentemente en producción

Ecosistema Maduro

  • Bibliotecas estándar robustas: STL, Boost, ASIO para networking
  • Herramientas de testing: Google Test, Catch2
  • Profiling avanzado: Valgrind, gprof, perf

Aplicación en la Industria

C++ es ampliamente utilizado en:

  • Sistemas de alta frecuencia (trading, telecomunicaciones)
  • Motores de juegos (Unreal Engine, Unity C++)
  • Sistemas embebidos y de tiempo real
  • Aplicaciones de alto rendimiento (bases de datos, servidores web)

Índice

Paso 1: Introducción a patrones avanzados

Los patrones avanzados de diseño se enfocan en resolver problemas de arquitectura a gran escala, especialmente en sistemas distribuidos y aplicaciones empresariales complejas.

¿Por qué son importantes?

  • Escalabilidad: Permiten manejar crecimiento exponencial
  • Resiliencia: Sistemas que se recuperan de fallos automáticamente
  • Mantenibilidad: Arquitecturas que evolucionan sin romperse
  • Performance: Optimización para cargas de trabajo intensivas

Patrones avanzados comunes

Patrón Propósito Complejidad
Circuit Breaker Prevenir fallos en cascada Media
API Gateway Punto de entrada único Alta
Microservicios Arquitectura distribuida Alta
CQRS Separar lecturas/escrituras Alta
Event Sourcing Almacenar eventos en lugar de estado Alta
Saga Pattern Transacciones distribuidas Alta

Paso 2: Circuit Breaker - Tolerancia a fallos

El patrón Circuit Breaker previene fallos en cascada en sistemas distribuidos, detectando fallos y evitando llamadas repetidas a servicios que están fallando.

Implementación básica

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <functional>
#include <stdexcept>
#include <random>
#include <memory>

enum class EstadoCircuitBreaker {
    CERRADO,      // Funcionamiento normal
    ABIERTO,      // Circuito abierto, no permite llamadas
    MEDIO_ABIERTO // Probando si el servicio se recuperó
};

class CircuitBreaker {
public:
    CircuitBreaker(const std::string& nombre, int umbral_fallos = 3, int tiempo_timeout_segundos = 5)
        : nombre_(nombre), umbral_fallos_(umbral_fallos), tiempo_timeout_segundos_(tiempo_timeout_segundos),
          estado_(EstadoCircuitBreaker::CERRADO), contador_fallos_(0) {}

    template<typename Func, typename... Args>
    auto ejecutar(Func&& funcion, Args&&... args) -> decltype(funcion(args...)) {
        auto tiempo_actual = std::chrono::steady_clock::now();

        if (estado_ == EstadoCircuitBreaker::ABIERTO) {
            // Verificar si es tiempo de intentar recuperación
            auto tiempo_desde_fallo = tiempo_actual - ultimo_fallo_tiempo_;
            if (tiempo_desde_fallo > std::chrono::seconds(tiempo_timeout_segundos_)) {
                estado_ = EstadoCircuitBreaker::MEDIO_ABIERTO;
                std::cout << "🔄 " << nombre_ << ": Cambiando a estado MEDIO_ABIERTO" << std::endl;
            } else {
                throw std::runtime_error("Circuito " + nombre_ + " ABIERTO - Servicio no disponible");
            }
        }

        try {
            auto resultado = std::forward<Func>(funcion)(std::forward<Args>(args)...);

            // Si la llamada es exitosa, resetear contadores
            if (estado_ == EstadoCircuitBreaker::MEDIO_ABIERTO) {
                estado_ = EstadoCircuitBreaker::CERRADO;
                contador_fallos_ = 0;
                std::cout << "✅ " << nombre_ << ": Servicio recuperado, circuito CERRADO" << std::endl;
            }

            ultimo_exito_tiempo_ = tiempo_actual;
            return resultado;

        } catch (const std::exception& e) {
            contador_fallos_++;
            ultimo_fallo_tiempo_ = tiempo_actual;

            std::cout << "❌ " << nombre_ << ": Fallo #" << contador_fallos_ << " - " << e.what() << std::endl;

            if (estado_ == EstadoCircuitBreaker::CERRADO && contador_fallos_ >= umbral_fallos_) {
                estado_ = EstadoCircuitBreaker::ABIERTO;
                std::cout << "🚨 " << nombre_ << ": Umbral de fallos alcanzado, circuito ABIERTO" << std::endl;
            } else if (estado_ == EstadoCircuitBreaker::MEDIO_ABIERTO) {
                estado_ = EstadoCircuitBreaker::ABIERTO;
                std::cout << "🚨 " << nombre_ << ": Fallo en prueba de recuperación, circuito ABIERTO" << std::endl;
            }

            throw;
        }
    }

private:
    std::string nombre_;
    int umbral_fallos_;
    int tiempo_timeout_segundos_;
    EstadoCircuitBreaker estado_;
    int contador_fallos_;
    std::chrono::steady_clock::time_point ultimo_fallo_tiempo_;
    std::chrono::steady_clock::time_point ultimo_exito_tiempo_;
};

// Servicio externo simulado con fallos
class ServicioExterno {
public:
    ServicioExterno(double tasa_fallo = 0.3) : tasa_fallo_(tasa_fallo), llamadas_(0) {}

    std::string llamar() {
        llamadas_++;

        // Simular fallo aleatorio
        static std::random_device rd;
        static std::mt19937 gen(rd());
        std::uniform_real_distribution<> dis(0.0, 1.0);

        if (dis(gen) < tasa_fallo_) {
            throw std::runtime_error("Servicio externo no disponible");
        }

        return "Respuesta del servicio #" + std::to_string(llamadas_);
    }

private:
    double tasa_fallo_;
    int llamadas_;
};

// Cliente que usa Circuit Breaker
class ClienteServicio {
public:
    ClienteServicio(std::shared_ptr<ServicioExterno> servicio)
        : servicio_(servicio) {
        circuit_breaker_ = std::make_unique<CircuitBreaker>(
            "servicio_externo", 2, 3
        );
    }

    std::string hacer_llamada() {
        return circuit_breaker_->ejecutar([this]() { return servicio_->llamar(); });
    }

private:
    std::shared_ptr<ServicioExterno> servicio_;
    std::unique_ptr<CircuitBreaker> circuit_breaker_;
};

// Demo
void demo_circuit_breaker() {
    auto servicio = std::make_shared<ServicioExterno>(0.7);  // 70% de fallos
    ClienteServicio cliente(servicio);

    for (int i = 0; i < 10; ++i) {
        try {
            std::string resultado = cliente.hacer_llamada();
            std::cout << "✅ Llamada " << (i+1) << ": " << resultado << std::endl;
        } catch (const std::exception& e) {
            std::cout << "❌ Llamada " << (i+1) << ": " << e.what() << std::endl;
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
}

int main() {
    demo_circuit_breaker();
    return 0;
}

Paso 3: API Gateway - Puerta de enlace

El patrón API Gateway actúa como punto de entrada único para todas las solicitudes, manejando enrutamiento, composición y transformación.

Implementación básica

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <chrono>
#include <thread>
#include <stdexcept>
#include <algorithm>
#include <sstream>

// Estructuras para Request/Response
struct Request {
    std::string method;
    std::string path;
    std::map<std::string, std::string> headers;
    std::string body;
    std::map<std::string, std::string> query_params;
};

struct Response {
    int status_code;
    std::map<std::string, std::string> headers;
    std::string body;

    Response(int code, const std::string& body_content = "")
        : status_code(code), body(body_content) {}
};

// Clase base abstracta para Gateway
class Gateway {
public:
    virtual ~Gateway() = default;
    virtual Response manejar_request(const Request& request) = 0;
};

// Gateway simple
class GatewaySimple : public Gateway {
public:
    GatewaySimple() = default;

    void agregar_ruta(const std::string& path, const std::string& destino) {
        rutas_[path] = destino;
    }

    void agregar_middleware(std::unique_ptr<class Middleware> middleware) {
        middlewares_.push_back(std::move(middleware));
    }

    Response manejar_request(const Request& request) override {
        Request processed_request = request;

        // Aplicar middlewares pre-procesamiento
        for (const auto& middleware : middlewares_) {
            processed_request = middleware->pre_procesar(processed_request);
        }

        // Enrutar
        std::string destino = encontrar_destino(request.path);
        if (destino.empty()) {
            return Response(404, "{\"error\": \"Ruta no encontrada\"}");
        }

        Response response(200);

        // Procesar request
        try {
            if (destino.find("http") == 0) {
                // Llamada HTTP
                response = llamar_servicio_externo(processed_request, destino);
            } else {
                // Lógica interna
                response = procesar_interno(processed_request, destino);
            }
        } catch (const std::exception& e) {
            response = Response(500, "{\"error\": \"" + std::string(e.what()) + "\"}");
        }

        // Aplicar middlewares post-procesamiento
        for (auto it = middlewares_.rbegin(); it != middlewares_.rend(); ++it) {
            response = (*it)->post_procesar(response);
        }

        return response;
    }

private:
    std::map<std::string, std::string> rutas_;
    std::vector<std::unique_ptr<class Middleware>> middlewares_;

    std::string encontrar_destino(const std::string& path) {
        for (const auto& [ruta, destino] : rutas_) {
            if (path.find(ruta) == 0) {
                return destino;
            }
        }
        return "";
    }

    Response llamar_servicio_externo(const Request& request, const std::string& destino) {
        std::string url = destino + request.path;

        // Simular llamada HTTP
        std::cout << "🔄 Llamando a " << url << " con método " << request.method << std::endl;

        // En un caso real usaríamos una librería como curl o boost::asio
        if (request.method == "GET") {
            return Response(200, "{\"data\": \"Respuesta de " + destino + "\"}");
        } else {
            return Response(200, "{\"message\": \"Operación completada\"}");
        }
    }

    Response procesar_interno(const Request& request, const std::string& destino) {
        if (destino == "auth") {
            return procesar_auth(request);
        } else if (destino == "metrics") {
            return procesar_metrics(request);
        } else {
            return Response(404, "{\"error\": \"Destino interno no encontrado\"}");
        }
    }

    Response procesar_auth(const Request& request) {
        auto it = request.headers.find("Authorization");
        std::string token = (it != request.headers.end()) ? it->second : "";

        if (token == "Bearer valid-token") {
            return Response(200, "{\"authenticated\": true, \"user\": \"admin\"}");
        } else {
            return Response(401, "{\"error\": \"No autorizado\"}");
        }
    }

    Response procesar_metrics(const Request& request) {
        return Response(200, "{\"requests_handled\": 1000, \"uptime\": \"24h\", \"status\": \"healthy\"}");
    }
};

// Clase base abstracta para Middleware
class Middleware {
public:
    virtual ~Middleware() = default;
    virtual Request pre_procesar(const Request& request) { return request; }
    virtual Response post_procesar(const Response& response) { return response; }
};

// Middleware de logging
class LoggingMiddleware : public Middleware {
public:
    Request pre_procesar(const Request& request) override {
        std::cout << "📝 Request: " << request.method << " " << request.path << std::endl;
        return request;
    }

    Response post_procesar(const Response& response) override {
        std::cout << "📝 Response: " << response.status_code << std::endl;
        return response;
    }
};

// Middleware de autenticación
class AuthMiddleware : public Middleware {
public:
    Request pre_procesar(const Request& request) override {
        // Rutas que no requieren autenticación
        std::vector<std::string> rutas_publicas = {"/auth", "/health", "/metrics"};
        bool es_ruta_publica = std::any_of(rutas_publicas.begin(), rutas_publicas.end(),
            [&request](const std::string& ruta) {
                return request.path.find(ruta) == 0;
            });

        if (es_ruta_publica) {
            return request;
        }

        // Verificar token
        auto it = request.headers.find("Authorization");
        std::string token = (it != request.headers.end()) ? it->second : "";

        if (token != "Bearer valid-token") {
            throw std::runtime_error("No autorizado");
        }

        return request;
    }
};

// Middleware de rate limiting
class RateLimitingMiddleware : public Middleware {
public:
    RateLimitingMiddleware(int limite_por_segundo = 10)
        : limite_(limite_por_segundo), contador_(0) {}

    Request pre_procesar(const Request& request) override {
        auto ahora = std::chrono::steady_clock::now();
        auto tiempo_desde_reset = ahora - ultimo_reset_;

        if (tiempo_desde_reset > std::chrono::seconds(1)) {
            contador_ = 0;
            ultimo_reset_ = ahora;
        }

        if (contador_ >= limite_) {
            throw std::runtime_error("Límite de tasa excedido");
        }

        contador_++;
        return request;
    }

private:
    int limite_;
    int contador_;
    std::chrono::steady_clock::time_point ultimo_reset_;
};

// Demo
void demo_api_gateway() {
    auto gateway = std::make_unique<GatewaySimple>();

    // Configurar rutas
    gateway->agregar_ruta("/api/users", "http://users-service:3000");
    gateway->agregar_ruta("/api/products", "http://products-service:3001");
    gateway->agregar_ruta("/auth", "auth");
    gateway->agregar_ruta("/metrics", "metrics");

    // Agregar middlewares
    gateway->agregar_middleware(std::make_unique<LoggingMiddleware>());
    gateway->agregar_middleware(std::make_unique<AuthMiddleware>());
    gateway->agregar_middleware(std::make_unique<RateLimitingMiddleware>(5));

    // Simular requests
    std::vector<Request> requests = {
        {"GET", "/auth", {{"Authorization", "Bearer valid-token"}}, "", {}},
        {"GET", "/api/users", {{"Authorization", "Bearer valid-token"}}, "", {}},
        {"GET", "/metrics", {{"Authorization", "Bearer valid-token"}}, "", {}},
        {"GET", "/api/products", {{"Authorization", "invalid-token"}}, "", {}}
    };

    for (size_t i = 0; i < requests.size(); ++i) {
        std::cout << "\n--- Request " << (i+1) << " ---" << std::endl;
        try {
            Response response = gateway->manejar_request(requests[i]);
            std::cout << "✅ Status: " << response.status_code << std::endl;
            std::cout << "Body: " << response.body << std::endl;
        } catch (const std::exception& e) {
            std::cout << "❌ Error: " << e.what() << std::endl;
        }
    }
}

int main() {
    demo_api_gateway();
    return 0;
}

Paso 4: Arquitectura de microservicios

La arquitectura de microservicios estructura una aplicación como una colección de servicios débilmente acoplados.

Ejemplo de microservicios

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <chrono>
#include <stdexcept>
#include <algorithm>

// Usuario
struct Usuario {
    int id;
    std::string nombre;
    std::string email;
    std::chrono::steady_clock::time_point fecha_creacion;

    Usuario(int id, const std::string& nombre, const std::string& email)
        : id(id), nombre(nombre), email(email),
          fecha_creacion(std::chrono::steady_clock::now()) {}
};

// Producto
struct Producto {
    int id;
    std::string nombre;
    double precio;
    int stock;

    Producto(int id, const std::string& nombre, double precio)
        : id(id), nombre(nombre), precio(precio), stock(0) {}
};

// Pedido
struct Pedido {
    int id;
    int usuario_id;
    std::vector<std::map<std::string, int>> items;  // {producto_id, cantidad}
    double total;
    std::string estado;
    std::chrono::steady_clock::time_point fecha_creacion;

    Pedido(int id, int usuario_id)
        : id(id), usuario_id(usuario_id), total(0.0), estado("creado"),
          fecha_creacion(std::chrono::steady_clock::now()) {}
};

// Servicio de usuarios
class ServicioUsuarios {
public:
    ServicioUsuarios() = default;

    Usuario crear_usuario(const std::string& nombre, const std::string& email) {
        int usuario_id = usuarios_.size() + 1;
        Usuario usuario(usuario_id, nombre, email);
        usuarios_[usuario_id] = usuario;
        return usuario;
    }

    std::shared_ptr<Usuario> obtener_usuario(int id) {
        auto it = usuarios_.find(id);
        if (it != usuarios_.end()) {
            return std::make_shared<Usuario>(it->second);
        }
        return nullptr;
    }

    std::vector<Usuario> listar_usuarios() {
        std::vector<Usuario> resultado;
        for (const auto& [id, usuario] : usuarios_) {
            resultado.push_back(usuario);
        }
        return resultado;
    }

private:
    std::map<int, Usuario> usuarios_;
};

// Servicio de productos
class ServicioProductos {
public:
    ServicioProductos() = default;

    Producto crear_producto(const std::string& nombre, double precio) {
        int producto_id = productos_.size() + 1;
        Producto producto(producto_id, nombre, precio);
        productos_[producto_id] = producto;
        return producto;
    }

    bool actualizar_stock(int producto_id, int cantidad) {
        auto it = productos_.find(producto_id);
        if (it != productos_.end()) {
            it->second.stock += cantidad;
            return true;
        }
        return false;
    }

    std::shared_ptr<Producto> obtener_producto(int id) {
        auto it = productos_.find(id);
        if (it != productos_.end()) {
            return std::make_shared<Producto>(it->second);
        }
        return nullptr;
    }

    std::vector<Producto> listar_productos() {
        std::vector<Producto> resultado;
        for (const auto& [id, producto] : productos_) {
            resultado.push_back(producto);
        }
        return resultado;
    }

private:
    std::map<int, Producto> productos_;
};

// Servicio de pedidos (orquestador)
class ServicioPedidos {
public:
    ServicioPedidos(std::shared_ptr<ServicioUsuarios> servicio_usuarios,
                    std::shared_ptr<ServicioProductos> servicio_productos)
        : servicio_usuarios_(servicio_usuarios),
          servicio_productos_(servicio_productos) {}

    Pedido crear_pedido(int usuario_id, const std::vector<std::map<std::string, int>>& items) {
        // Verificar usuario
        auto usuario = servicio_usuarios_->obtener_usuario(usuario_id);
        if (!usuario) {
            throw std::runtime_error("Usuario no encontrado");
        }

        // Verificar productos y stock
        double total = 0.0;
        for (const auto& item : items) {
            int producto_id = item.at("producto_id");
            int cantidad = item.at("cantidad");

            auto producto = servicio_productos_->obtener_producto(producto_id);
            if (!producto) {
                throw std::runtime_error("Producto " + std::to_string(producto_id) + " no encontrado");
            }
            if (producto->stock < cantidad) {
                throw std::runtime_error("Stock insuficiente para producto " + producto->nombre);
            }

            total += producto->precio * cantidad;
        }

        // Crear pedido
        int pedido_id = pedidos_.size() + 1;
        Pedido pedido(pedido_id, usuario_id);
        pedido.items = items;
        pedido.total = total;
        pedidos_[pedido_id] = pedido;

        // Actualizar stock (en un caso real sería transaccional)
        for (const auto& item : items) {
            servicio_productos_->actualizar_stock(item.at("producto_id"), -item.at("cantidad"));
        }

        return pedido;
    }

    std::vector<Pedido> listar_pedidos() {
        std::vector<Pedido> resultado;
        for (const auto& [id, pedido] : pedidos_) {
            resultado.push_back(pedido);
        }
        return resultado;
    }

private:
    std::shared_ptr<ServicioUsuarios> servicio_usuarios_;
    std::shared_ptr<ServicioProductos> servicio_productos_;
    std::map<int, Pedido> pedidos_;
};

// Service Discovery
class ServiceDiscovery {
public:
    ServiceDiscovery() = default;

    void registrar_servicio(const std::string& nombre, std::shared_ptr<void> instancia) {
        servicios_[nombre] = instancia;
    }

    template<typename T>
    std::shared_ptr<T> obtener_servicio(const std::string& nombre) {
        auto it = servicios_.find(nombre);
        if (it != servicios_.end()) {
            return std::static_pointer_cast<T>(it->second);
        }
        return nullptr;
    }

private:
    std::map<std::string, std::shared_ptr<void>> servicios_;
};

// Configuración del sistema de microservicios
std::unique_ptr<ServiceDiscovery> configurar_microservicios() {
    auto discovery = std::make_unique<ServiceDiscovery>();

    // Crear servicios
    auto servicio_usuarios = std::make_shared<ServicioUsuarios>();
    auto servicio_productos = std::make_shared<ServicioProductos>();
    auto servicio_pedidos = std::make_shared<ServicioPedidos>(servicio_usuarios, servicio_productos);

    // Registrar servicios
    discovery->registrar_servicio<ServicioUsuarios>("usuarios", servicio_usuarios);
    discovery->registrar_servicio<ServicioProductos>("productos", servicio_productos);
    discovery->registrar_servicio<ServicioPedidos>("pedidos", servicio_pedidos);

    return discovery;
}

// Demo
void demo_microservicios() {
    auto discovery = configurar_microservicios();

    // Obtener servicios
    auto usuarios = discovery->obtener_servicio<ServicioUsuarios>("usuarios");
    auto productos = discovery->obtener_servicio<ServicioProductos>("productos");
    auto pedidos = discovery->obtener_servicio<ServicioPedidos>("pedidos");

    if (!usuarios || !productos || !pedidos) {
        std::cout << "Error: No se pudieron obtener los servicios" << std::endl;
        return;
    }

    // Crear datos de prueba
    Usuario usuario = usuarios->crear_usuario("Ana García", "[email protected]");
    std::cout << "Usuario creado: " << usuario.nombre << std::endl;

    Producto producto1 = productos->crear_producto("Laptop", 1200.00);
    Producto producto2 = productos->crear_producto("Mouse", 45.99);
    productos->actualizar_stock(producto1.id, 10);
    productos->actualizar_stock(producto2.id, 20);

    auto productos_lista = productos->listar_productos();
    std::cout << "Productos creados: " << productos_lista.size() << std::endl;

    // Crear pedido
    std::vector<std::map<std::string, int>> items = {
        {{"producto_id", producto1.id}, {"cantidad", 1}},
        {{"producto_id", producto2.id}, {"cantidad", 2}}
    };

    try {
        Pedido pedido = pedidos->crear_pedido(usuario.id, items);
        std::cout << "Pedido creado: $" << pedido.total << std::endl;
        std::cout << "Estado: " << pedido.estado << std::endl;
    } catch (const std::exception& e) {
        std::cout << "Error al crear pedido: " << e.what() << std::endl;
    }

    // Mostrar estado final
    auto usuarios_lista = usuarios->listar_usuarios();
    auto productos_lista_final = productos->listar_productos();
    auto pedidos_lista = pedidos->listar_pedidos();

    std::cout << "Usuarios: " << usuarios_lista.size() << std::endl;
    std::cout << "Productos: " << productos_lista_final.size() << std::endl;
    std::cout << "Pedidos: " << pedidos_lista.size() << std::endl;
}

int main() {
    demo_microservicios();
    return 0;
}

Paso 5: CQRS - Separación de lecturas y escrituras

El patrón CQRS (Command Query Responsibility Segregation) separa las operaciones de lectura y escritura en modelos diferentes.

Implementación básica

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <stdexcept>
#include <algorithm>
#include <chrono>

// Commands - Escrituras
struct CrearUsuarioCommand {
    std::string nombre;
    std::string email;
    std::string direccion;

    CrearUsuarioCommand(const std::string& n, const std::string& e, const std::string& d)
        : nombre(n), email(e), direccion(d) {}
};

struct CrearProductoCommand {
    std::string nombre;
    double precio;
    std::string categoria;
    int stock;

    CrearProductoCommand(const std::string& n, double p, const std::string& c, int s = 0)
        : nombre(n), precio(p), categoria(c), stock(s) {}
};

// Queries - Lecturas
struct ObtenerUsuarioQuery {
    std::string usuario_id;

    ObtenerUsuarioQuery(const std::string& id) : usuario_id(id) {}
};

struct ListarProductosQuery {
    std::string categoria;

    ListarProductosQuery(const std::string& cat = "") : categoria(cat) {}
};

// Modelos de datos
struct Usuario {
    std::string id;
    std::string nombre;
    std::string email;
    std::string direccion;
    std::chrono::steady_clock::time_point fecha_creacion;

    Usuario(const std::string& id, const std::string& n, const std::string& e, const std::string& d)
        : id(id), nombre(n), email(e), direccion(d),
          fecha_creacion(std::chrono::steady_clock::now()) {}
};

struct Producto {
    std::string id;
    std::string nombre;
    double precio;
    std::string categoria;
    int stock;

    Producto(const std::string& id, const std::string& n, double p, const std::string& c, int s = 0)
        : id(id), nombre(n), precio(p), categoria(c), stock(s) {}
};

// Command Handler base
class CommandHandler {
public:
    virtual ~CommandHandler() = default;
    virtual void manejar(const void* command) = 0;
};

// Query Handler base
class QueryHandler {
public:
    virtual ~QueryHandler() = default;
    virtual void* manejar(const void* query) = 0;
};

// Repositorios
class RepositorioUsuarios {
public:
    RepositorioUsuarios() = default;

    void guardar(const Usuario& usuario) {
        usuarios_[usuario.id] = usuario;
    }

    std::shared_ptr<Usuario> obtener_por_id(const std::string& id) {
        auto it = usuarios_.find(id);
        if (it != usuarios_.end()) {
            return std::make_shared<Usuario>(it->second);
        }
        return nullptr;
    }

    std::vector<Usuario> listar_todos() {
        std::vector<Usuario> resultado;
        for (const auto& [id, usuario] : usuarios_) {
            resultado.push_back(usuario);
        }
        return resultado;
    }

private:
    std::map<std::string, Usuario> usuarios_;
};

class RepositorioProductos {
public:
    RepositorioProductos() = default;

    void guardar(const Producto& producto) {
        productos_[producto.id] = producto;
    }

    std::shared_ptr<Producto> obtener_por_id(const std::string& id) {
        auto it = productos_.find(id);
        if (it != productos_.end()) {
            return std::make_shared<Producto>(it->second);
        }
        return nullptr;
    }

    std::vector<Producto> listar_todos() {
        std::vector<Producto> resultado;
        for (const auto& [id, producto] : productos_) {
            resultado.push_back(producto);
        }
        return resultado;
    }

private:
    std::map<std::string, Producto> productos_;
};

// Command Handlers
class CrearUsuarioHandler : public CommandHandler {
public:
    CrearUsuarioHandler(std::shared_ptr<RepositorioUsuarios> repo) : repositorio_(repo) {}

    void manejar(const void* command) override {
        const auto* cmd = static_cast<const CrearUsuarioCommand*>(command);

        // Validar que el email no exista
        auto usuarios = repositorio_->listar_todos();
        for (const auto& usuario : usuarios) {
            if (usuario.email == cmd->email) {
                throw std::runtime_error("Email ya registrado");
            }
        }

        std::string usuario_id = generar_id();
        Usuario usuario(usuario_id, cmd->nombre, cmd->email, cmd->direccion);
        repositorio_->guardar(usuario);

        // Guardar resultado para acceso posterior
        resultado_ = std::make_shared<Usuario>(usuario);
    }

    std::shared_ptr<Usuario> obtener_resultado() { return resultado_; }

private:
    std::shared_ptr<RepositorioUsuarios> repositorio_;
    std::shared_ptr<Usuario> resultado_;

    std::string generar_id() {
        static int contador = 0;
        return "user_" + std::to_string(++contador);
    }
};

class CrearProductoHandler : public CommandHandler {
public:
    CrearProductoHandler(std::shared_ptr<RepositorioProductos> repo) : repositorio_(repo) {}

    void manejar(const void* command) override {
        const auto* cmd = static_cast<const CrearProductoCommand*>(command);

        std::string producto_id = generar_id();
        Producto producto(producto_id, cmd->nombre, cmd->precio, cmd->categoria, cmd->stock);
        repositorio_->guardar(producto);

        resultado_ = std::make_shared<Producto>(producto);
    }

    std::shared_ptr<Producto> obtener_resultado() { return resultado_; }

private:
    std::shared_ptr<RepositorioProductos> repositorio_;
    std::shared_ptr<Producto> resultado_;

    std::string generar_id() {
        static int contador = 0;
        return "prod_" + std::to_string(++contador);
    }
};

// Query Handlers
class ObtenerUsuarioHandler : public QueryHandler {
public:
    ObtenerUsuarioHandler(std::shared_ptr<RepositorioUsuarios> repo) : repositorio_(repo) {}

    void* manejar(const void* query) override {
        const auto* q = static_cast<const ObtenerUsuarioQuery*>(query);
        return repositorio_->obtener_por_id(q->usuario_id).release();
    }

private:
    std::shared_ptr<RepositorioUsuarios> repositorio_;
};

class ListarProductosHandler : public QueryHandler {
public:
    ListarProductosHandler(std::shared_ptr<RepositorioProductos> repo) : repositorio_(repo) {}

    void* manejar(const void* query) override {
        const auto* q = static_cast<const ListarProductosQuery*>(query);

        auto productos = repositorio_->listar_todos();
        if (!q->categoria.empty()) {
            productos.erase(
                std::remove_if(productos.begin(), productos.end(),
                    [q](const Producto& p) { return p.categoria != q->categoria; }),
                productos.end()
            );
        }

        auto* resultado = new std::vector<Producto>(productos);
        return resultado;
    }

private:
    std::shared_ptr<RepositorioProductos> repositorio_;
};

// Bus de comandos y consultas
class CommandBus {
public:
    CommandBus() = default;

    void registrar_handler(std::type_index tipo, std::unique_ptr<CommandHandler> handler) {
        handlers_[tipo] = std::move(handler);
    }

    void enviar(std::unique_ptr<void> command) {
        std::type_index tipo = std::type_index(typeid(*command));
        auto it = handlers_.find(tipo);
        if (it == handlers_.end()) {
            throw std::runtime_error("No hay handler para el comando");
        }
        it->second->manejar(command.get());
    }

private:
    std::map<std::type_index, std::unique_ptr<CommandHandler>> handlers_;
};

class QueryBus {
public:
    QueryBus() = default;

    void registrar_handler(std::type_index tipo, std::unique_ptr<QueryHandler> handler) {
        handlers_[tipo] = std::move(handler);
    }

    std::unique_ptr<void> enviar(std::unique_ptr<void> query) {
        std::type_index tipo = std::type_index(typeid(*query));
        auto it = handlers_.find(tipo);
        if (it == handlers_.end()) {
            throw std::runtime_error("No hay handler para la consulta");
        }
        return std::unique_ptr<void>(it->second->manejar(query.get()));
    }

private:
    std::map<std::type_index, std::unique_ptr<QueryHandler>> handlers_;
};

// Demo CQRS
void demo_cqrs() {
    // Configurar repositorios
    auto repo_usuarios = std::make_shared<RepositorioUsuarios>();
    auto repo_productos = std::make_shared<RepositorioProductos>();

    // Configurar command bus
    CommandBus command_bus;
    command_bus.registrar_handler(
        std::type_index(typeid(CrearUsuarioCommand)),
        std::make_unique<CrearUsuarioHandler>(repo_usuarios)
    );
    command_bus.registrar_handler(
        std::type_index(typeid(CrearProductoCommand)),
        std::make_unique<CrearProductoHandler>(repo_productos)
    );

    // Configurar query bus
    QueryBus query_bus;
    query_bus.registrar_handler(
        std::type_index(typeid(ObtenerUsuarioQuery)),
        std::make_unique<ObtenerUsuarioHandler>(repo_usuarios)
    );
    query_bus.registrar_handler(
        std::type_index(typeid(ListarProductosQuery)),
        std::make_unique<ListarProductosHandler>(repo_productos)
    );

    // Ejecutar comandos (escrituras)
    std::cout << "=== Ejecutando Comandos ===" << std::endl;

    auto cmd_usuario = std::make_unique<CrearUsuarioCommand>(
        "Ana García", "[email protected]", "Calle Principal 123"
    );
    command_bus.enviar(std::move(cmd_usuario));

    auto cmd_producto1 = std::make_unique<CrearProductoCommand>(
        "Laptop Gaming", 1200.00, "tecnologia", 10
    );
    command_bus.enviar(std::move(cmd_producto1));

    auto cmd_producto2 = std::make_unique<CrearProductoCommand>(
        "Mouse Inalámbrico", 45.99, "tecnologia", 20
    );
    command_bus.enviar(std::move(cmd_producto2));

    std::cout << "Productos creados: " << repo_productos->listar_todos().size() << std::endl;

    // Ejecutar consultas (lecturas)
    std::cout << "\n=== Ejecutando Consultas ===" << std::endl;

    auto query_usuario = std::make_unique<ObtenerUsuarioQuery>("user_1");
    auto usuario_result = query_bus.enviar(std::move(query_usuario));
    auto usuario = static_cast<Usuario*>(usuario_result.get());
    std::cout << "Usuario consultado: " << usuario->nombre << std::endl;

    auto query_productos = std::make_unique<ListarProductosQuery>("tecnologia");
    auto productos_result = query_bus.enviar(std::move(query_productos));
    auto productos = static_cast<std::vector<Producto>*>(productos_result.get());
    std::cout << "Productos de tecnología: " << productos->size() << std::endl;

    for (const auto& producto : *productos) {
        std::cout << "  - " << producto.nombre << ": $" << producto.precio << std::endl;
    }

    // Liberar memoria
    delete usuario;
    delete productos;
}

int main() {
    demo_cqrs();
    return 0;
}

Paso 6: Event Sourcing - Fuente de eventos

El patrón Event Sourcing almacena el estado de una aplicación como una secuencia de eventos en lugar de solo el estado actual.

Implementación básica

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <chrono>
#include <stdexcept>
#include <algorithm>
#include <sstream>

// Evento base
struct Evento {
    std::string id;
    std::string tipo;
    std::map<std::string, std::string> datos;
    std::chrono::steady_clock::time_point timestamp;
    int version;

    Evento(const std::string& tipo_evento, const std::map<std::string, std::string>& datos_evento)
        : tipo(tipo_evento), datos(datos_evento), timestamp(std::chrono::steady_clock::now()), version(1) {
        static int contador = 0;
        id = "evt_" + std::to_string(++contador);
    }
};

// Eventos específicos
struct ProductoCreadoEvent : public Evento {
    ProductoCreadoEvent(const std::string& producto_id, const std::string& nombre,
                       double precio, const std::string& categoria)
        : Evento("ProductoCreado", {
            {"producto_id", producto_id},
            {"nombre", nombre},
            {"precio", std::to_string(precio)},
            {"categoria", categoria}
        }) {}
};

struct StockActualizadoEvent : public Evento {
    StockActualizadoEvent(const std::string& producto_id, int cantidad, int nuevo_stock)
        : Evento("StockActualizado", {
            {"producto_id", producto_id},
            {"cantidad", std::to_string(cantidad)},
            {"nuevo_stock", std::to_string(nuevo_stock)}
        }) {}
};

// Aggregate (Agregado)
class ProductoAggregate {
public:
    ProductoAggregate(const std::string& producto_id = "")
        : producto_id_(producto_id), nombre_(""), precio_(0.0), categoria_(""),
          stock_(0), version_(0) {}

    std::string crear(const std::string& nombre, double precio, const std::string& categoria, int stock = 0) {
        producto_id_ = generar_id();
        auto evento = std::make_shared<ProductoCreadoEvent>(producto_id_, nombre, precio, categoria);
        aplicar_cambio(evento);

        if (stock > 0) {
            actualizar_stock(stock);
        }

        return producto_id_;
    }

    void actualizar_stock(int cantidad) {
        int nuevo_stock = stock_ + cantidad;
        auto evento = std::make_shared<StockActualizadoEvent>(producto_id_, cantidad, nuevo_stock);
        aplicar_cambio(evento);
    }

    void aplicar_cambio(std::shared_ptr<Evento> evento) {
        cambios_pendientes_.push_back(evento);
        aplicar(*evento);
    }

    void aplicar(const Evento& evento) {
        if (evento.tipo == "ProductoCreado") {
            nombre_ = evento.datos.at("nombre");
            precio_ = std::stod(evento.datos.at("precio"));
            categoria_ = evento.datos.at("categoria");
        } else if (evento.tipo == "StockActualizado") {
            stock_ = std::stoi(evento.datos.at("nuevo_stock"));
        }

        version_++;
    }

    std::vector<std::shared_ptr<Evento>> obtener_cambios() {
        return cambios_pendientes_;
    }

    void limpiar_cambios() {
        cambios_pendientes_.clear();
    }

    // Getters
    std::string get_producto_id() const { return producto_id_; }
    std::string get_nombre() const { return nombre_; }
    double get_precio() const { return precio_; }
    std::string get_categoria() const { return categoria_; }
    int get_stock() const { return stock_; }
    int get_version() const { return version_; }

private:
    std::string producto_id_;
    std::string nombre_;
    double precio_;
    std::string categoria_;
    int stock_;
    int version_;
    std::vector<std::shared_ptr<Evento>> cambios_pendientes_;

    std::string generar_id() {
        static int contador = 0;
        return "prod_" + std::to_string(++contador);
    }
};

// Event Store
class EventStore {
public:
    EventStore() = default;

    void guardar_eventos(const std::string& aggregate_id,
                        const std::vector<std::shared_ptr<Evento>>& eventos,
                        int version_esperada) {
        if (eventos_.find(aggregate_id) == eventos_.end()) {
            eventos_[aggregate_id] = {};
        }

        // Verificar concurrencia (optimistic concurrency)
        if (version_esperada != -1 && eventos_[aggregate_id].size() != static_cast<size_t>(version_esperada)) {
            throw std::runtime_error("Concurrency conflict");
        }

        for (const auto& evento : eventos) {
            eventos_[aggregate_id].push_back(evento);
        }
    }

    std::vector<std::shared_ptr<Evento>> obtener_eventos(const std::string& aggregate_id) {
        auto it = eventos_.find(aggregate_id);
        if (it != eventos_.end()) {
            return it->second;
        }
        return {};
    }

    std::vector<std::shared_ptr<Evento>> obtener_todos_eventos() {
        std::vector<std::shared_ptr<Evento>> todos_eventos;
        for (const auto& [aggregate_id, eventos] : eventos_) {
            todos_eventos.insert(todos_eventos.end(), eventos.begin(), eventos.end());
        }

        std::sort(todos_eventos.begin(), todos_eventos.end(),
            [](const std::shared_ptr<Evento>& a, const std::shared_ptr<Evento>& b) {
                return a->timestamp < b->timestamp;
            });

        return todos_eventos;
    }

private:
    std::map<std::string, std::vector<std::shared_ptr<Evento>>> eventos_;
};

// Repository para Event Sourcing
class ProductoRepository {
public:
    ProductoRepository(std::shared_ptr<EventStore> event_store) : event_store_(event_store) {}

    void guardar(std::shared_ptr<ProductoAggregate> producto) {
        auto eventos = producto->obtener_cambios();
        int version_esperada = event_store_->obtener_eventos(producto->get_producto_id()).size();
        event_store_->guardar_eventos(producto->get_producto_id(), eventos, version_esperada);
        producto->limpiar_cambios();
    }

    std::shared_ptr<ProductoAggregate> obtener_por_id(const std::string& producto_id) {
        auto eventos = event_store_->obtener_eventos(producto_id);
        if (eventos.empty()) {
            return nullptr;
        }

        auto producto = std::make_shared<ProductoAggregate>(producto_id);
        for (const auto& evento : eventos) {
            producto->aplicar(*evento);
        }

        return producto;
    }

private:
    std::shared_ptr<EventStore> event_store_;
};

// Proyecciones (Projections)
class ProductoProjection {
public:
    ProductoProjection(std::shared_ptr<EventStore> event_store) : event_store_(event_store) {}

    void actualizar() {
        auto eventos = event_store_->obtener_todos_eventos();
        for (const auto& evento : eventos) {
            if (evento->tipo == "ProductoCreado") {
                productos_[evento->datos.at("producto_id")] = {
                    {"nombre", evento->datos.at("nombre")},
                    {"precio", evento->datos.at("precio")},
                    {"categoria", evento->datos.at("categoria")},
                    {"stock", "0"}
                };
            } else if (evento->tipo == "StockActualizado") {
                auto it = productos_.find(evento->datos.at("producto_id"));
                if (it != productos_.end()) {
                    it->second["stock"] = evento->datos.at("nuevo_stock");
                }
            }
        }
    }

    std::vector<std::map<std::string, std::string>> obtener_todos() {
        std::vector<std::map<std::string, std::string>> resultado;
        for (const auto& [id, producto] : productos_) {
            resultado.push_back(producto);
        }
        return resultado;
    }

    std::vector<std::map<std::string, std::string>> obtener_por_categoria(const std::string& categoria) {
        std::vector<std::map<std::string, std::string>> resultado;
        for (const auto& [id, producto] : productos_) {
            if (producto.at("categoria") == categoria) {
                resultado.push_back(producto);
            }
        }
        return resultado;
    }

private:
    std::shared_ptr<EventStore> event_store_;
    std::map<std::string, std::map<std::string, std::string>> productos_;
};

// Demo Event Sourcing
void demo_event_sourcing() {
    // Configurar
    auto event_store = std::make_shared<EventStore>();
    auto producto_repo = std::make_shared<ProductoRepository>(event_store);
    auto projection = std::make_shared<ProductoProjection>(event_store);

    std::cout << "=== Event Sourcing Demo ===" << std::endl;

    // Crear producto con eventos
    auto producto = std::make_shared<ProductoAggregate>();
    producto->crear("Laptop Gaming", 1200.00, "tecnologia", 10);
    producto_repo->guardar(producto);

    std::cout << "Producto creado: " << producto->get_nombre() << std::endl;
    std::cout << "Stock inicial: " << producto->get_stock() << std::endl;

    // Actualizar stock con eventos
    producto->actualizar_stock(5);
    producto_repo->guardar(producto);

    std::cout << "Stock después de agregar 5: " << producto->get_stock() << std::endl;

    // Cargar desde eventos
    std::cout << "\n=== Cargando desde Event Store ===" << std::endl;
    auto producto_cargado = producto_repo->obtener_por_id(producto->get_producto_id());
    if (producto_cargado) {
        std::cout << "Producto cargado: " << producto_cargado->get_nombre() << std::endl;
        std::cout << "Stock cargado: " << producto_cargado->get_stock() << std::endl;
    }

    // Usar proyección
    std::cout << "\n=== Usando Proyección ===" << std::endl;
    projection->actualizar();
    auto productos = projection->obtener_todos();
    std::cout << "Productos en proyección: " << productos.size() << std::endl;

    for (const auto& p : productos) {
        std::cout << "  - " << p.at("nombre") << ": $" << p.at("precio")
                  << " (Stock: " << p.at("stock") << ")" << std::endl;
    }

    // Mostrar todos los eventos
    std::cout << "\n=== Todos los Eventos ===" << std::endl;
    auto eventos = event_store->obtener_todos_eventos();
    for (const auto& evento : eventos) {
        std::cout << evento->tipo << ": ";
        for (const auto& [clave, valor] : evento->datos) {
            std::cout << clave << "=" << valor << " ";
        }
        std::cout << std::endl;
    }
}

int main() {
    demo_event_sourcing();
    return 0;
}

Paso 7: Saga Pattern - Transacciones distribuidas

El patrón Saga maneja transacciones distribuidas de larga duración mediante una secuencia de transacciones locales.

Implementación básica

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <functional>
#include <chrono>
#include <thread>
#include <stdexcept>
#include <random>
#include <algorithm>

enum class EstadoSaga {
    INICIADA,
    EN_PROGRESO,
    COMPLETADA,
    COMPENSANDO,
    COMPENSADA,
    FALLIDA
};

struct Saga {
    std::string id;
    std::string tipo;
    std::vector<std::shared_ptr<struct PasoSaga>> pasos;
    EstadoSaga estado;
    std::map<std::string, std::string> datos;
    std::chrono::steady_clock::time_point fecha_creacion;
    std::chrono::steady_clock::time_point fecha_actualizacion;

    Saga(const std::string& id_saga, const std::string& tipo_saga,
         const std::map<std::string, std::string>& datos_iniciales)
        : id(id_saga), tipo(tipo_saga), estado(EstadoSaga::INICIADA),
          datos(datos_iniciales),
          fecha_creacion(std::chrono::steady_clock::now()),
          fecha_actualizacion(std::chrono::steady_clock::now()) {}
};

struct PasoSaga {
    std::string nombre;
    std::function<std::map<std::string, std::string>(const std::map<std::string, std::string>&)> accion;
    std::function<void(const std::map<std::string, std::string>&)> compensacion;
    int orden;

    PasoSaga(const std::string& nombre_paso,
             std::function<std::map<std::string, std::string>(const std::map<std::string, std::string>&)> accion_func,
             std::function<void(const std::map<std::string, std::string>&)> compensacion_func,
             int orden_paso)
        : nombre(nombre_paso), accion(accion_func), compensacion(compensacion_func), orden(orden_paso) {}
};

class SagaManager {
public:
    SagaManager() = default;

    void registrar_paso(const std::string& nombre,
                       std::function<std::map<std::string, std::string>(const std::map<std::string, std::string>&)> accion,
                       std::function<void(const std::map<std::string, std::string>&)> compensacion) {
        pasos_registrados_[nombre] = std::make_shared<PasoSaga>(
            nombre, accion, compensacion, static_cast<int>(pasos_registrados_.size())
        );
    }

    std::shared_ptr<Saga> iniciar_saga(const std::string& tipo, const std::map<std::string, std::string>& datos_iniciales) {
        std::string saga_id = generar_id();
        auto saga = std::make_shared<Saga>(saga_id, tipo, datos_iniciales);
        sagas_[saga_id] = saga;
        return saga;
    }

    void agregar_paso(const std::string& saga_id, const std::string& nombre_paso) {
        auto saga_it = sagas_.find(saga_id);
        if (saga_it == sagas_.end()) {
            throw std::runtime_error("Saga no encontrada");
        }

        auto paso_it = pasos_registrados_.find(nombre_paso);
        if (paso_it == pasos_registrados_.end()) {
            throw std::runtime_error("Paso '" + nombre_paso + "' no registrado");
        }

        auto saga = saga_it->second;
        auto paso_base = paso_it->second;

        // Crear nueva instancia del paso para esta saga
        auto nuevo_paso = std::make_shared<PasoSaga>(
            paso_base->nombre, paso_base->accion, paso_base->compensacion,
            static_cast<int>(saga->pasos.size())
        );
        saga->pasos.push_back(nuevo_paso);
        saga->fecha_actualizacion = std::chrono::steady_clock::now();
    }

    std::shared_ptr<Saga> ejecutar_saga(const std::string& saga_id) {
        auto saga_it = sagas_.find(saga_id);
        if (saga_it == sagas_.end()) {
            throw std::runtime_error("Saga no encontrada");
        }

        auto saga = saga_it->second;
        saga->estado = EstadoSaga::EN_PROGRESO;
        saga->fecha_actualizacion = std::chrono::steady_clock::now();

        std::vector<std::shared_ptr<PasoSaga>> pasos_ejecutados;

        try {
            for (size_t i = 0; i < saga->pasos.size(); ++i) {
                auto paso = saga->pasos[i];
                std::cout << "🏃 Ejecutando paso " << (i+1) << ": " << paso->nombre << std::endl;

                // Ejecutar acción
                auto resultado = paso->accion(saga->datos);
                for (const auto& [clave, valor] : resultado) {
                    saga->datos[clave] = valor;
                }

                pasos_ejecutados.push_back(paso);
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
            }

            saga->estado = EstadoSaga::COMPLETADA;
            std::cout << "✅ Saga completada exitosamente" << std::endl;

        } catch (const std::exception& e) {
            std::cout << "❌ Error en saga: " << e.what() << std::endl;
            saga->estado = EstadoSaga::FALLIDA;
            compensar_saga(saga, pasos_ejecutados);
        }

        saga->fecha_actualizacion = std::chrono::steady_clock::now();
        return saga;
    }

private:
    std::map<std::string, std::shared_ptr<Saga>> sagas_;
    std::map<std::string, std::shared_ptr<PasoSaga>> pasos_registrados_;

    void compensar_saga(std::shared_ptr<Saga> saga, const std::vector<std::shared_ptr<PasoSaga>>& pasos_ejecutados) {
        saga->estado = EstadoSaga::COMPENSANDO;
        std::cout << "🔄 Compensando saga..." << std::endl;

        // Compensar en orden inverso
        for (auto it = pasos_ejecutados.rbegin(); it != pasos_ejecutados.rend(); ++it) {
            try {
                std::cout << "↩️ Compensando paso: " << (*it)->nombre << std::endl;
                (*it)->compensacion(saga->datos);
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
            } catch (const std::exception& e) {
                std::cout << "⚠️ Error compensando paso " << (*it)->nombre << ": " << e.what() << std::endl;
            }
        }

        saga->estado = EstadoSaga::COMPENSADA;
        std::cout << "✅ Saga compensada" << std::endl;
    }

    std::string generar_id() {
        static int contador = 0;
        return "saga_" + std::to_string(++contador);
    }
};

// Servicios para la saga
class ServicioInventario {
public:
    std::map<std::string, std::string> reservar_stock(const std::map<std::string, std::string>& datos) {
        std::string producto_id = datos.at("producto_id");
        int cantidad = std::stoi(datos.at("cantidad"));
        std::cout << "📦 Reservando " << cantidad << " unidades del producto " << producto_id << std::endl;

        // Simular fallo aleatorio
        static std::random_device rd;
        static std::mt19937 gen(rd());
        std::uniform_real_distribution<> dis(0.0, 1.0);

        if (dis(gen) < 0.3) {
            throw std::runtime_error("Error al reservar stock");
        }

        return {{"stock_reservado", "true"}};
    }

    void compensar_reserva(const std::map<std::string, std::string>& datos) {
        std::string producto_id = datos.at("producto_id");
        int cantidad = std::stoi(datos.at("cantidad"));
        std::cout << "↩️ Liberando reserva de " << cantidad << " unidades del producto " << producto_id << std::endl;
    }
};

class ServicioPagos {
public:
    std::map<std::string, std::string> procesar_pago(const std::map<std::string, std::string>& datos) {
        std::string usuario_id = datos.at("usuario_id");
        double monto = std::stod(datos.at("monto"));
        std::cout << "💳 Procesando pago de $" << monto << " para usuario " << usuario_id << std::endl;

        // Simular fallo aleatorio
        static std::random_device rd;
        static std::mt19937 gen(rd());
        std::uniform_real_distribution<> dis(0.0, 1.0);

        if (dis(gen) < 0.3) {
            throw std::runtime_error("Error al procesar pago");
        }

        static int contador_transaccion = 0;
        std::string id_transaccion = "txn_" + std::to_string(++contador_transaccion);
        return {
            {"pago_procesado", "true"},
            {"id_transaccion", id_transaccion}
        };
    }

    void compensar_pago(const std::map<std::string, std::string>& datos) {
        std::string id_transaccion = datos.at("id_transaccion");
        std::cout << "↩️ Reembolsando pago " << id_transaccion << std::endl;
    }
};

class ServicioEnvio {
public:
    std::map<std::string, std::string> programar_envio(const std::map<std::string, std::string>& datos) {
        std::string usuario_id = datos.at("usuario_id");
        std::string direccion = datos.at("direccion");
        std::cout << "🚚 Programando envío para usuario " << usuario_id << " a " << direccion << std::endl;

        static int contador_guia = 0;
        std::string numero_guia = "guia_" + std::to_string(++contador_guia);
        return {
            {"envio_programado", "true"},
            {"numero_guia", numero_guia}
        };
    }

    void cancelar_envio(const std::map<std::string, std::string>& datos) {
        std::string numero_guia = datos.at("numero_guia");
        std::cout << "↩️ Cancelando envío " << numero_guia << std::endl;
    }
};

// Demo Saga Pattern
void demo_saga_pattern() {
    // Configurar servicios
    ServicioInventario inventario;
    ServicioPagos pagos;
    ServicioEnvio envio;

    // Configurar saga manager
    SagaManager manager;

    // Registrar pasos
    manager.registrar_paso(
        "reservar_stock",
        [&inventario](const auto& datos) { return inventario.reservar_stock(datos); },
        [&inventario](const auto& datos) { inventario.compensar_reserva(datos); }
    );

    manager.registrar_paso(
        "procesar_pago",
        [&pagos](const auto& datos) { return pagos.procesar_pago(datos); },
        [&pagos](const auto& datos) { pagos.compensar_pago(datos); }
    );

    manager.registrar_paso(
        "programar_envio",
        [&envio](const auto& datos) { return envio.programar_envio(datos); },
        [&envio](const auto& datos) { envio.cancelar_envio(datos); }
    );

    // Datos iniciales
    std::map<std::string, std::string> datos_pedido = {
        {"usuario_id", "user_123"},
        {"producto_id", "prod_456"},
        {"cantidad", "2"},
        {"monto", "99.99"},
        {"direccion", "Calle Principal 123"}
    };

    // Crear y configurar saga
    auto saga = manager.iniciar_saga("procesar_pedido", datos_pedido);
    manager.agregar_paso(saga->id, "reservar_stock");
    manager.agregar_paso(saga->id, "procesar_pago");
    manager.agregar_paso(saga->id, "programar_envio");

    // Ejecutar saga
    std::cout << "=== Iniciando Saga de Procesamiento de Pedido ===" << std::endl;
    auto resultado = manager.ejecutar_saga(saga->id);

    std::cout << "\nEstado final: ";
    switch (resultado->estado) {
        case EstadoSaga::COMPLETADA: std::cout << "COMPLETADA"; break;
        case EstadoSaga::FALLIDA: std::cout << "FALLIDA"; break;
        case EstadoSaga::COMPENSADA: std::cout << "COMPENSADA"; break;
        default: std::cout << "DESCONOCIDO"; break;
    }
    std::cout << std::endl;

    std::cout << "Datos finales:" << std::endl;
    for (const auto& [clave, valor] : resultado->datos) {
        std::cout << "  " << clave << ": " << valor << std::endl;
    }
}

int main() {
    demo_saga_pattern();
    return 0;
}

Paso 8: Caso de estudio - Sistema de e-commerce

Vamos a crear un sistema completo de e-commerce usando múltiples patrones avanzados.

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <chrono>
#include <stdexcept>
#include <algorithm>

// Domain Models
struct Producto {
    std::string id;
    std::string nombre;
    double precio;
    int stock;
    std::string categoria;

    Producto(const std::string& id, const std::string& nombre, double precio,
             const std::string& categoria, int stock = 0)
        : id(id), nombre(nombre), precio(precio), stock(stock), categoria(categoria) {}
};

struct Usuario {
    std::string id;
    std::string nombre;
    std::string email;
    std::string direccion;

    Usuario(const std::string& id, const std::string& nombre, const std::string& email,
            const std::string& direccion)
        : id(id), nombre(nombre), email(email), direccion(direccion) {}
};

struct Pedido {
    std::string id;
    std::string usuario_id;
    std::vector<std::map<std::string, std::string>> items;
    double total;
    std::string estado;
    std::chrono::steady_clock::time_point fecha_creacion;

    Pedido(const std::string& id, const std::string& usuario_id)
        : id(id), usuario_id(usuario_id), total(0.0), estado("creado"),
          fecha_creacion(std::chrono::steady_clock::now()) {}
};

// Repositories
class RepositorioProductos {
public:
    RepositorioProductos() = default;

    std::shared_ptr<Producto> guardar(const Producto& producto) {
        productos_[producto.id] = std::make_shared<Producto>(producto);
        return productos_[producto.id];
    }

    std::shared_ptr<Producto> obtener_por_id(const std::string& id) {
        auto it = productos_.find(id);
        if (it != productos_.end()) {
            return it->second;
        }
        return nullptr;
    }

    std::vector<std::shared_ptr<Producto>> obtener_todos() {
        std::vector<std::shared_ptr<Producto>> resultado;
        for (const auto& [id, producto] : productos_) {
            resultado.push_back(producto);
        }
        return resultado;
    }

    bool actualizar_stock(const std::string& id, int cantidad) {
        auto producto = obtener_por_id(id);
        if (producto) {
            producto->stock += cantidad;
            return true;
        }
        return false;
    }

private:
    std::map<std::string, std::shared_ptr<Producto>> productos_;
};

class RepositorioUsuarios {
public:
    RepositorioUsuarios() = default;

    std::shared_ptr<Usuario> guardar(const Usuario& usuario) {
        usuarios_[usuario.id] = std::make_shared<Usuario>(usuario);
        return usuarios_[usuario.id];
    }

    std::shared_ptr<Usuario> obtener_por_id(const std::string& id) {
        auto it = usuarios_.find(id);
        if (it != usuarios_.end()) {
            return it->second;
        }
        return nullptr;
    }

    std::shared_ptr<Usuario> obtener_por_email(const std::string& email) {
        for (const auto& [id, usuario] : usuarios_) {
            if (usuario->email == email) {
                return usuario;
            }
        }
        return nullptr;
    }

private:
    std::map<std::string, std::shared_ptr<Usuario>> usuarios_;
};

class RepositorioPedidos {
public:
    RepositorioPedidos() = default;

    std::shared_ptr<Pedido> guardar(const Pedido& pedido) {
        pedidos_[pedido.id] = std::make_shared<Pedido>(pedido);
        return pedidos_[pedido.id];
    }

    std::shared_ptr<Pedido> obtener_por_id(const std::string& id) {
        auto it = pedidos_.find(id);
        if (it != pedidos_.end()) {
            return it->second;
        }
        return nullptr;
    }

    std::vector<std::shared_ptr<Pedido>> obtener_por_usuario(const std::string& usuario_id) {
        std::vector<std::shared_ptr<Pedido>> resultado;
        for (const auto& [id, pedido] : pedidos_) {
            if (pedido->usuario_id == usuario_id) {
                resultado.push_back(pedido);
            }
        }
        return resultado;
    }

private:
    std::map<std::string, std::shared_ptr<Pedido>> pedidos_;
};

// Services
class ServicioCatalogo {
public:
    ServicioCatalogo(std::shared_ptr<RepositorioProductos> repositorio)
        : repositorio_(repositorio) {}

    std::shared_ptr<Producto> crear_producto(const std::string& nombre, double precio,
                                           const std::string& categoria, int stock = 0) {
        std::string producto_id = generar_id();
        Producto producto(producto_id, nombre, precio, categoria, stock);
        return repositorio_->guardar(producto);
    }

    std::vector<std::shared_ptr<Producto>> listar_productos(const std::string& categoria = "") {
        auto productos = repositorio_->obtener_todos();
        if (!categoria.empty()) {
            productos.erase(
                std::remove_if(productos.begin(), productos.end(),
                    [categoria](const std::shared_ptr<Producto>& p) {
                        return p->categoria != categoria;
                    }),
                productos.end()
            );
        }
        return productos;
    }

    std::shared_ptr<Producto> obtener_producto(const std::string& id) {
        return repositorio_->obtener_por_id(id);
    }

private:
    std::shared_ptr<RepositorioProductos> repositorio_;

    std::string generar_id() {
        static int contador = 0;
        return "prod_" + std::to_string(++contador);
    }
};

class ServicioUsuarios {
public:
    ServicioUsuarios(std::shared_ptr<RepositorioUsuarios> repositorio)
        : repositorio_(repositorio) {}

    std::shared_ptr<Usuario> registrar_usuario(const std::string& nombre, const std::string& email,
                                             const std::string& direccion) {
        // Verificar si ya existe
        if (repositorio_->obtener_por_email(email)) {
            throw std::runtime_error("Email ya registrado");
        }

        std::string usuario_id = generar_id();
        Usuario usuario(usuario_id, nombre, email, direccion);
        return repositorio_->guardar(usuario);
    }

    std::shared_ptr<Usuario> obtener_usuario(const std::string& id) {
        return repositorio_->obtener_por_id(id);
    }

private:
    std::shared_ptr<RepositorioUsuarios> repositorio_;

    std::string generar_id() {
        static int contador = 0;
        return "user_" + std::to_string(++contador);
    }
};

class ServicioPedidos {
public:
    ServicioPedidos(std::shared_ptr<RepositorioPedidos> repositorio_pedidos,
                   std::shared_ptr<RepositorioProductos> repositorio_productos,
                   std::shared_ptr<RepositorioUsuarios> repositorio_usuarios)
        : repositorio_pedidos_(repositorio_pedidos),
          repositorio_productos_(repositorio_productos),
          repositorio_usuarios_(repositorio_usuarios) {}

    std::shared_ptr<Pedido> crear_pedido(const std::string& usuario_id,
                                       const std::vector<std::map<std::string, std::string>>& items) {
        // Verificar usuario
        auto usuario = repositorio_usuarios_->obtener_por_id(usuario_id);
        if (!usuario) {
            throw std::runtime_error("Usuario no encontrado");
        }

        // Verificar productos y calcular total
        double total = 0.0;
        for (const auto& item : items) {
            std::string producto_id = item.at("producto_id");
            int cantidad = std::stoi(item.at("cantidad"));

            auto producto = repositorio_productos_->obtener_por_id(producto_id);
            if (!producto) {
                throw std::runtime_error("Producto " + producto_id + " no encontrado");
            }
            if (producto->stock < cantidad) {
                throw std::runtime_error("Stock insuficiente para " + producto->nombre);
            }

            total += producto->precio * cantidad;
        }

        // Crear pedido
        std::string pedido_id = generar_id();
        Pedido pedido(pedido_id, usuario_id);
        pedido.items = items;
        pedido.total = total;

        // Actualizar stock
        for (const auto& item : items) {
            std::string producto_id = item.at("producto_id");
            int cantidad = std::stoi(item.at("cantidad"));
            repositorio_productos_->actualizar_stock(producto_id, -cantidad);
        }

        return repositorio_pedidos_->guardar(pedido);
    }

    bool cancelar_pedido(const std::string& pedido_id) {
        auto pedido = repositorio_pedidos_->obtener_por_id(pedido_id);
        if (!pedido || pedido->estado == "cancelado") {
            return false;
        }

        // Revertir stock
        for (const auto& item : pedido->items) {
            std::string producto_id = item.at("producto_id");
            int cantidad = std::stoi(item.at("cantidad"));
            repositorio_productos_->actualizar_stock(producto_id, cantidad);
        }

        pedido->estado = "cancelado";
        return true;
    }

private:
    std::shared_ptr<RepositorioPedidos> repositorio_pedidos_;
    std::shared_ptr<RepositorioProductos> repositorio_productos_;
    std::shared_ptr<RepositorioUsuarios> repositorio_usuarios_;

    std::string generar_id() {
        static int contador = 0;
        return "ped_" + std::to_string(++contador);
    }
};

// API Gateway
class ECommerceGateway {
public:
    ECommerceGateway(std::shared_ptr<ServicioCatalogo> servicio_catalogo,
                    std::shared_ptr<ServicioUsuarios> servicio_usuarios,
                    std::shared_ptr<ServicioPedidos> servicio_pedidos)
        : servicio_catalogo_(servicio_catalogo),
          servicio_usuarios_(servicio_usuarios),
          servicio_pedidos_(servicio_pedidos) {}

    std::map<std::string, std::string> manejar_request(const std::string& metodo,
                                                     const std::string& ruta,
                                                     const std::map<std::string, std::string>& datos) {
        try {
            if (metodo == "GET" && ruta == "/productos") {
                std::string categoria = datos.at("categoria");
                auto productos = servicio_catalogo_->listar_productos(categoria.empty() ? "" : categoria);

                std::vector<std::map<std::string, std::string>> productos_data;
                for (const auto& producto : productos) {
                    productos_data.push_back({
                        {"id", producto->id},
                        {"nombre", producto->nombre},
                        {"precio", std::to_string(producto->precio)},
                        {"stock", std::to_string(producto->stock)},
                        {"categoria", producto->categoria}
                    });
                }

                return {
                    {"status", "200"},
                    {"data", "productos_data"}  // En un caso real, serializar a JSON
                };

            } else if (metodo == "POST" && ruta == "/usuarios") {
                auto usuario = servicio_usuarios_->registrar_usuario(
                    datos.at("nombre"), datos.at("email"), datos.at("direccion")
                );

                return {
                    {"status", "201"},
                    {"data", usuario->id}
                };

            } else if (metodo == "POST" && ruta == "/pedidos") {
                std::string usuario_id = datos.at("usuario_id");
                // Convertir items string a vector de maps (simplificado)
                std::vector<std::map<std::string, std::string>> items;

                auto pedido = servicio_pedidos_->crear_pedido(usuario_id, items);

                return {
                    {"status", "201"},
                    {"data", pedido->id}
                };

            } else if (metodo == "POST" && ruta == "/pedidos/cancelar") {
                std::string pedido_id = datos.at("pedido_id");
                bool exito = servicio_pedidos_->cancelar_pedido(pedido_id);

                return {
                    {"status", "200"},
                    {"data", exito ? "true" : "false"}
                };

            } else {
                return {
                    {"status", "404"},
                    {"error", "Ruta no encontrada"}
                };

            }
        } catch (const std::exception& e) {
            return {
                {"status", "400"},
                {"error", e.what()}
            };
        }
    }

private:
    std::shared_ptr<ServicioCatalogo> servicio_catalogo_;
    std::shared_ptr<ServicioUsuarios> servicio_usuarios_;
    std::shared_ptr<ServicioPedidos> servicio_pedidos_;
};

// Demo del sistema completo
void demo_ecommerce() {
    // Configurar repositorios
    auto repo_productos = std::make_shared<RepositorioProductos>();
    auto repo_usuarios = std::make_shared<RepositorioUsuarios>();
    auto repo_pedidos = std::make_shared<RepositorioPedidos>();

    // Configurar servicios
    auto servicio_catalogo = std::make_shared<ServicioCatalogo>(repo_productos);
    auto servicio_usuarios = std::make_shared<ServicioUsuarios>(repo_usuarios);
    auto servicio_pedidos = std::make_shared<ServicioPedidos>(repo_pedidos, repo_productos, repo_usuarios);

    // Configurar gateway
    ECommerceGateway gateway(servicio_catalogo, servicio_usuarios, servicio_pedidos);

    // Crear productos
    auto producto1 = servicio_catalogo->crear_producto("Laptop Gaming", 1200.00, "tecnologia", 10);
    auto producto2 = servicio_catalogo->crear_producto("Mouse Inalámbrico", 45.99, "tecnologia", 20);
    auto producto3 = servicio_catalogo->crear_producto("Silla Ergonómica", 299.99, "muebles", 5);

    std::cout << "🛍️  Productos creados:" << std::endl;
    for (const auto& p : {producto1, producto2, producto3}) {
        std::cout << "  - " << p->nombre << ": $" << p->precio << " (Stock: " << p->stock << ")" << std::endl;
    }

    // Registrar usuario
    auto usuario = servicio_usuarios->registrar_usuario(
        "Ana García", "[email protected]", "Calle Principal 123"
    );
    std::cout << "\n👤 Usuario registrado: " << usuario->nombre << " (" << usuario->email << ")" << std::endl;

    // Crear pedido a través del gateway
    std::map<std::string, std::string> datos_pedido = {
        {"usuario_id", usuario->id},
        {"items", "[]"}  // Simplificado
    };

    auto response = gateway.manejar_request("POST", "/pedidos", datos_pedido);

    if (response.at("status") == "201") {
        std::cout << "\n📦 Pedido creado exitosamente:" << std::endl;
        std::cout << "   ID: " << response.at("data") << std::endl;
        std::cout << "   Estado: creado" << std::endl;
    } else {
        std::cout << "\n❌ Error al crear pedido: " << response.at("error") << std::endl;
    }

    // Mostrar estado actual
    auto productos_lista = servicio_catalogo->listar_productos();
    auto usuarios_lista = repo_usuarios->obtener_por_id(usuario->id);
    auto pedidos_lista = repo_pedidos->obtener_por_usuario(usuario->id);

    std::cout << "\n📊 Estado actual:" << std::endl;
    std::cout << "   Productos en stock: " << productos_lista.size() << std::endl;
    std::cout << "   Usuarios registrados: " << (usuarios_lista ? 1 : 0) << std::endl;
    std::cout << "   Pedidos realizados: " << pedidos_lista.size() << std::endl;

    // Mostrar stock actualizado
    std::cout << "\n📦 Stock actualizado:" << std::endl;
    for (const auto& producto : productos_lista) {
        std::cout << "   " << producto->nombre << ": " << producto->stock << " unidades" << std::endl;
    }
}

int main() {
    demo_ecommerce();
    return 0;
}

Paso 9: Consideraciones de rendimiento y escalabilidad

Patrones para alta escalabilidad

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <chrono>
#include <thread>
#include <functional>
#include <queue>
#include <mutex>
#include <atomic>

// Caching con Redis/Memcached (simulado)
class Cache {
public:
    Cache() = default;

    std::string get(const std::string& key, const std::string& default_value = "") {
        std::lock_guard<std::mutex> lock(mutex_);
        auto it = cache_.find(key);
        if (it != cache_.end()) {
            return it->second;
        }
        return default_value;
    }

    void set(const std::string& key, const std::string& value, int ttl_segundos = 300) {
        std::lock_guard<std::mutex> lock(mutex_);
        cache_[key] = value;
        // En un caso real, aquí se manejaría TTL
    }

    void del(const std::string& key) {
        std::lock_guard<std::mutex> lock(mutex_);
        cache_.erase(key);
    }

private:
    std::map<std::string, std::string> cache_;
    std::mutex mutex_;
};

// Load Balancer
class LoadBalancer {
public:
    LoadBalancer(const std::vector<std::string>& servidores)
        : servidores_(servidores), indice_(0) {}

    std::string siguiente_servidor() {
        std::string servidor = servidores_[indice_];
        indice_ = (indice_ + 1) % servidores_.size();
        return servidor;
    }

private:
    std::vector<std::string> servidores_;
    std::atomic<int> indice_;
};

// Database Sharding
class ShardManager {
public:
    ShardManager(const std::vector<std::string>& shards) : shards_(shards) {}

    std::string obtener_shard(const std::string& clave) {
        // Hash simple para determinar shard
        size_t hash_val = std::hash<std::string>{}(clave) % shards_.size();
        return shards_[hash_val];
    }

private:
    std::vector<std::string> shards_;
};

// Message Queue para procesamiento asíncrono
class MessageQueue {
public:
    MessageQueue() = default;

    void publicar(const std::string& topico, const std::string& mensaje) {
        std::lock_guard<std::mutex> lock(mutex_);
        colas_[topico].push(mensaje);
    }

    std::string consumir(const std::string& topico) {
        std::lock_guard<std::mutex> lock(mutex_);
        auto it = colas_.find(topico);
        if (it != colas_.end() && !it->second.empty()) {
            std::string mensaje = it->second.front();
            it->second.pop();
            return mensaje;
        }
        return "";
    }

private:
    std::map<std::string, std::queue<std::string>> colas_;
    std::mutex mutex_;
};

// Ejemplo de sistema escalable
class SistemaEscalable {
public:
    SistemaEscalable()
        : cache_(std::make_shared<Cache>()),
          load_balancer_(std::make_shared<LoadBalancer>(std::vector<std::string>{"server1", "server2", "server3"})),
          message_queue_(std::make_shared<MessageQueue>()),
          shard_manager_(std::make_shared<ShardManager>(std::vector<std::string>{"shard1", "shard2", "shard3"})) {}

    std::string procesar_solicitud(const std::string& usuario_id, const std::string& accion, const std::string& datos) {
        // Verificar cache primero
        std::string cache_key = usuario_id + ":" + accion;
        std::string cached = cache_->get(cache_key);
        if (!cached.empty()) {
            return cached;
        }

        // Balancear carga
        std::string servidor = load_balancer_->siguiente_servidor();

        // Determinar shard
        std::string shard = shard_manager_->obtener_shard(usuario_id);

        // Procesar (simulado)
        std::string resultado = "Procesado en " + servidor + " usando " + shard;

        // Cachear resultado
        cache_->set(cache_key, resultado);

        // Publicar en cola para procesamiento asíncrono
        message_queue_->publicar("logs", usuario_id + " - " + accion);

        return resultado;
    }

    std::string consumir_log() {
        return message_queue_->consumir("logs");
    }

private:
    std::shared_ptr<Cache> cache_;
    std::shared_ptr<LoadBalancer> load_balancer_;
    std::shared_ptr<MessageQueue> message_queue_;
    std::shared_ptr<ShardManager> shard_manager_;
};

// Demo de escalabilidad
void demo_escalabilidad() {
    SistemaEscalable sistema;

    // Simular múltiples solicitudes
    std::vector<std::string> usuarios = {"user0", "user1", "user2", "user3", "user4",
                                       "user5", "user6", "user7", "user8", "user9"};
    std::vector<std::string> acciones = {"read", "write", "update", "delete"};

    for (int i = 0; i < 20; ++i) {
        std::string usuario = usuarios[i % usuarios.size()];
        std::string accion = acciones[i % acciones.size()];

        std::string resultado = sistema.procesar_solicitud(usuario, accion, "data" + std::to_string(i));
        std::cout << "Solicitud " << (i+1) << ": " << resultado << std::endl;

        // Simular procesamiento asíncrono
        std::string log = sistema.consumir_log();
        if (!log.empty()) {
            std::cout << "  📋 Log procesado: " << log << std::endl;
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(50));
    }
}

int main() {
    demo_escalabilidad();
    return 0;
}

Conclusión

¡Has dominado los patrones avanzados de diseño en C++! Estos patrones te permiten construir sistemas de alto rendimiento, escalables y mantenibles que pueden manejar la complejidad de aplicaciones empresariales modernas.

C++ es especialmente adecuado para estos patrones avanzados porque:

  • Performance: Control preciso sobre memoria y recursos
  • Type Safety: Compilación estricta que previene errores en tiempo de ejecución
  • Control de Recursos: RAII y smart pointers para gestión automática de memoria
  • Multi-threading: Soporte nativo para concurrencia de alto rendimiento
  • Flexibilidad: Templates y metaprogramación para patrones genéricos

Recuerda que cada patrón tiene su lugar y propósito. La clave está en entender cuándo y cómo aplicar cada uno según las necesidades específicas de tu proyecto.

Para más tutoriales sobre arquitectura avanzada y patrones de diseño en C++, visita nuestra sección de tutoriales.


¡Sigue practicando y aplicando estos patrones en proyectos reales!


💡 Tip Importante

📝 Mejores Prácticas para Patrones Avanzados en C++

  • Empieza simple: No implementes patrones complejos prematuramente
  • Mide el impacto: Evalúa si un patrón realmente resuelve un problema
  • Considera el costo: Algunos patrones añaden complejidad significativa
  • Documenta decisiones: Explica por qué elegiste ciertos patrones
  • Mantén la coherencia: Usa patrones consistentemente en todo el sistema
  • Prueba exhaustivamente: Los sistemas distribuidos requieren testing riguroso
  • Monitorea en producción: Supervisa el comportamiento real de los patrones
  • Aprende de fallos: Los patrones de resiliencia se prueban mejor con fallos reales
  • Evoluciona iterativamente: Refactoriza y mejora la arquitectura con el tiempo
  • Mantén la simplicidad: El mejor patrón es a menudo el más simple que funciona
  • Gestiona memoria: Usa smart pointers y RAII para evitar leaks
  • Thread safety: Considera concurrencia en patrones distribuidos
  • Compilación: Aprovecha el type checking de C++ para detectar errores tempranamente

📚 Recursos Recomendados para C++:

¡Estos recursos te ayudarán a profundizar en arquitecturas empresariales avanzadas con C++!

Toca los botones para interactuar

Comentarios

Comentarios

Inicia sesión para dejar un comentario.

No hay comentarios aún

Sé el primero en comentar este tutorial.

Tutoriales Relacionados

Descubre más tutoriales relacionados que podrían ser de tu interés

Imagen destacada del tutorial relacionado: Principios SOLID de Diseño de Software en C++
Patrones de Diseño

Principios SOLID de Diseño de Software en C++

Aprende los principios SOLID de diseño de software (SRP, OCP, LSP, ISP, DIP) con ejemplos prácticos en C++ y mejora la calidad de tu código con type safety y performance.

José Elías Romero Guanipa
01 Sep 2025
Imagen destacada del tutorial relacionado: Patrones de Diseño de Comportamiento en C++
Patrones de Diseño

Patrones de Diseño de Comportamiento en C++

Aprende patrones de diseño de comportamiento como Observer, Strategy, Command, State, Template Method, Iterator, Mediator y Memento con ejemplos prácticos en C++. Descubre cómo implementar estos patrones aprovechando las fortalezas del lenguaje C++ como type safety, performance y memory management.

José Elías Romero Guanipa
02 Sep 2025
Imagen destacada del tutorial relacionado: Patrones de Diseño Creacionales en C++
Patrones de Diseño

Patrones de Diseño Creacionales en C++

Aprende patrones de diseño creacionales como Singleton, Factory, Builder y Prototype con ejemplos prácticos en C++ moderno, aprovechando smart pointers, RAII y características del lenguaje.

José Elías Romero Guanipa
03 Sep 2025
Imagen destacada del tutorial relacionado: Patrones de Diseño Estructurales en C++
Patrones de Diseño

Patrones de Diseño Estructurales en C++

Aprende patrones de diseño estructurales como Adapter, Decorator, Facade y Proxy con ejemplos prácticos en C++, aprovechando las fortalezas del lenguaje para estructuras robustas y eficientes.

José Elías Romero Guanipa
04 Sep 2025
Foto de perfil del autor José Elías Romero Guanipa
José Elías Romero Guanipa
Autor

🌟 Nube de Etiquetas

Descubre temas populares en nuestros tutoriales

python
python 25 tutoriales
poo
poo 8 tutoriales
ciencia de datos
ciencia de datos 8 tutoriales
patrones diseño
patrones diseño 7 tutoriales
matplotlib
matplotlib 7 tutoriales
pandas
pandas 6 tutoriales
visualizacion
visualizacion 6 tutoriales
principiante
principiante 5 tutoriales
numpy
numpy 5 tutoriales
c++
c++ 5 tutoriales
estadistica
estadistica 4 tutoriales
cpp
cpp 4 tutoriales
bases de datos
bases de datos 4 tutoriales
dataframe
dataframe 4 tutoriales
csv
csv 3 tutoriales
json
json 3 tutoriales
machine learning
machine learning 3 tutoriales
rendimiento
rendimiento 3 tutoriales
mysql
mysql 3 tutoriales
postgresql
postgresql 3 tutoriales
analisis de datos
analisis de datos 3 tutoriales
graficos
graficos 3 tutoriales
excepciones
excepciones 2 tutoriales
algoritmos
algoritmos 2 tutoriales
estructuras datos
estructuras datos 2 tutoriales

Las etiquetas más grandes y brillantes aparecen en más tutoriales

logo logo

©2024 ViveBTC