🚨 ¡Nueva review! ✨ Mi ratón favorito para programar: el Logitech MX Master 3S . ¡Échale un ojo! 👀

El Patrón de diseño Proxy

Controla el acceso al objeto real de forma inteligente.

Escrito por domin el 4 de noviembre de 2025

🛡️ El Patrón Proxy: El Intermediario que lo peta

El Patrón Proxy, otro de los GangOfFour, tiene un objetivo superútil: proporcionar un sustituto o un marcador de posición para otro objeto. No es que haga el trabajo del objeto, sino que se pone delante de él para controlar quién y cómo puede acceder a sus funcionalidades.

El problema que resuelve es este:
¿Cómo puedes controlar el acceso a un objeto grande o sensible sin modificar su código, o cómo puedes optimizar su uso (como hacer una caché) sin que el cliente se dé cuenta?

La respuesta es creando un objeto Proxy que comparte la misma interfaz que el objeto original, y así, el cliente interactúa con el Proxy pensando que es el objeto real.

🛡️ 1. Un ejemplo sencillo: El portero de discoteca

Imagina que quieres entrar en una discoteca exclusiva (La discoteca sería el objeto real):

Concepto (Analogía)

Rol en Proxy

Tarea Principal

Discoteca Exclusiva

Sujeto Real

La clase que hace el trabajo pesado o sensible.

Portero

Proxy

Controla, restringe o optimiza el acceso al Sujeto Real.

Regla de Acceso (Ej. Mayores de 18)

Interfaz (Opcional, pero Recomendada)

Asegura que el Proxy y el Sujeto Real tengan los mismos métodos.

El truco está en que el Proxy implementa la misma interfaz que el Objeto Real, así que para el cliente, son indistinguibles. Puedes cambiar un objeto por su proxy y el código del cliente seguirá funcionando.

🛠️ 2. Los tres pilares del patrón Proxy

El Proxy necesita tres roles principales para funcionar correctamente:

1. El Sujeto (La Interfaz Común)

2. El Sujeto Real (El Objeto Original)

3. El Proxy (El Sustituto/Guardián)

🤔 1. ¿Qué característica es esencial para que un Proxy pueda ser un sustituto de un Objeto Real sin que el Cliente lo note?

💾 3. El ejemplo clásico: Un servicio de descargas con control

Imagina un servicio donde la acción de descargar() tarda mucho tiempo (es el Objeto Real). Queremos evitar que usuarios no premium puedan hacer la descarga.

Clase/Rol

Función (Ej. descargar)

Sujeto Real

Contiene la lógica pesada y lenta de descargarArchivoGrande().

Proxy de Descarga

Define el método descargarArchivoGrande() que, antes de delegar, llama a verificarPermisos() (la lógica de control).

El código del cliente solo llama a servicio->descargarArchivoGrande(...) sin saber si está hablando con el Proxy o el Objeto Real. Si usa el Proxy, este lo protegerá.

🤔 2. Si un Proxy implementa un mecanismo de caché para guardar resultados, ¿qué tipo de Proxy es más probable que sea?

✅ 4. ¿Por Qué Usarlo?

El Proxy te da un control asombroso sin modificar el código original (que puede ser de una librería externa que no puedes tocar):

  1. Control de Acceso: Puedes implementar seguridad (permisos de usuario, rate limiting) antes de que el objeto real se ejecute.
  2. Optimización (Lazy Loading): Puedes evitar inicializar un objeto muy costoso en memoria hasta el momento exacto en que se necesita (Proxy Virtual).
  3. Registro (Logging): Puedes registrar llamadas (quién llamó a qué método y cuándo) sin ensuciar la lógica del objeto real.

❌ 5. Desventaja a Considerar

🤔 3. ¿Cuál de estos es un beneficio de usar un Proxy Virtual?

💡 6. Conclusión

El Patrón Proxy es tu mejor amigo cuando necesitas interponer una capa de lógica entre un cliente y un objeto. Si la inicialización de un objeto es lenta, si quieres poner un peaje de seguridad, o si simplemente quieres guardar un registro de su uso, el Proxy te permite hacerlo de forma limpia y transparente para el cliente. Es como poner un filtro que añade valor sin alterar la esencia del objeto original.

🧠 7. Ejemplo Práctico en PHP

Vamos a implementar el patrón Proxy con el ejemplo de un servicio de descargas que restringe el acceso a usuarios que no son premium.

El cliente solo interactuará con la interfaz, sin saber si está usando el objeto real o el proxy.

<?php

// 🔹 1. El Sujeto (La Interfaz Común)
interface ServicioDeDescarga {
    public function descargar(string $archivo, string $usuario): bool;
}

// 🔹 2. El Sujeto Real (El objeto que hace el trabajo pesado)
class LibreriaDeDescargasPesadas implements ServicioDeDescarga {
    public function descargar(string $archivo, string $usuario): bool {
        echo "   [REAL] >> Conectando a servidor de descargas, proceso lento..." . PHP_EOL;
        // Lógica real de descarga (puede tardar segundos)
        echo "   [REAL] Archivo '$archivo' descargado con éxito para '$usuario'." . PHP_EOL;
        return true;
    }
}

// 🔹 3. El Proxy (El Guardián que añade control)
class ProxyDeDescargaPremium implements ServicioDeDescarga {
    private LibreriaDeDescargasPesadas $servicioReal;
    // Lista simple de usuarios premium para el ejemplo
    private array $usuariosPremium = ['cliente@premium.com', 'otro@vip.com'];

    public function __construct(LibreriaDeDescargasPesadas $servicioReal) {
        // El proxy guarda una referencia al objeto real
        $this->servicioReal = $servicioReal;
    }

    /**
     * El método del proxy que añade el control de acceso.
     */
    public function descargar(string $archivo, string $usuario): bool {
        echo "➡️ Iniciando proceso de descarga con Proxy..." . PHP_EOL;

        // 1. Lógica de Control de Acceso (El valor añadido del Proxy)
        if (!in_array($usuario, $this->usuariosPremium)) {
            echo "❌ ACCESO DENEGADO: El usuario '$usuario' no es Premium. No se puede acceder a la descarga." . PHP_EOL;
            return false;
        }

        echo "✅ Permisos verificados. El usuario '$usuario' es Premium." . PHP_EOL;

        // 2. Delegación al Objeto Real
        return $this->servicioReal->descargar($archivo, $usuario);
    }
}

// 🔹 4. Uso del patrón (El Cliente)
$servicioReal = new LibreriaDeDescargasPesadas();
$proxyPremium = new ProxyDeDescargaPremium($servicioReal);

echo "--- Intento de descarga de un usuario NO Premium ---" . PHP_EOL;
$proxyPremium->descargar('documento_secreto.zip', 'anonimo@gratis.com');

echo PHP_EOL . "--- Intento de descarga de un usuario PREMIUM ---" . PHP_EOL;
$proxyPremium->descargar('pelicula_4k.mkv', 'cliente@premium.com');


// 🖥️ Salida del programa:
// --- Intento de descarga de un usuario NO Premium ---
// ➡️ Iniciando proceso de descarga con Proxy...
// ❌ ACCESO DENEGADO: El usuario 'anonimo@gratis.com' no es Premium. No se puede acceder a la descarga.

// --- Intento de descarga de un usuario PREMIUM ---
// ➡️ Iniciando proceso de descarga con Proxy...
// ✅ Permisos verificados. El usuario 'cliente@premium.com' es Premium.
//    [REAL] >> Conectando a servidor de descargas, proceso lento...
//    [REAL] Archivo 'pelicula_4k.mkv' descargado con éxito para 'cliente@premium.com'.

EA, ¡saluditos y nos vemos en los bares! 🍻