El patrón de diseño Proxy, en el ámbito de la ingeniería de software, proporciona un sustituto o intermediario para otro objeto. Su objetivo principal es controlar el acceso al objeto real, añadiendo una capa de funcionalidad adicional sin modificar la lógica interna del objeto subyacente. Esta funcionalidad extra puede incluir verificación de accceso, registro de operaciones, inicialización perezosa (lazy initialization) o incluso gestión de caché. Tanto el objeto proxy como el objeto real impelmentan la misma interfaz, lo que permite que el cliente interactúe con el proxy de la misma manera que lo haría con el objeto real.
Estructura del Patrón
La estructura fundamental del patrón Proxy se compone de los siguientes elementos:
- Sujeto (Subject): Una interfaz común que tanto el Sujeto Real como el Proxy implementan. Esto permite que el cliente trate al proxy y al sujeto real de manera intercambiable.
- Sujeto Real (Real Subject): El objeto original que contiene la lógica de negocio principal que se desea proteger o extender.
- Proxy: Mantiene una referencia al Sujeto Real y controla el acceso a él. Puede realizar acciones antes o después de la llamada al objeto real.
- Cliente (Client): Interactúa con el Proxy para acceder a la funcionalidad del Sujeto Real.
La siguiente imagen ilustra la estructura de clases del patrón Proxy, mostrando cómo la interfaz es compartida entre el Sujeto Real y el Proxy, y cómo el Proxy encapsula al Sujeto Real para delegar o interceptar las operaciones.

Ejemplo de Implementación en Java
Consideremos un escenario práctico donde un sistema nceesita gestionar el envío de regalos a un destinatario. Un cliente desea enviar varios tipos de regalos, pero la lógica de envío real debe ser encapsulada y posiblemente supervisada por un intermediario. Aquí, un proxy puede controlar si el envío es autorizado antes de delegar la acción al gestor de regalos real.
1. Interfaz del Gestor de Regalos
Definimos una interfaz que especifica las operaciones de envío de regalos. Tanto el gestor real como el proxy implementarán esta interfaz.
package com.ejemplo.proxy.core;
public interface IGestorRegalos {
void enviarFlores();
void enviarMuñecos();
void enviarChocolates();
}
2. Clase Destinatario
Una clase simple que representa a la persona que recibirá los regalos.
package com.ejemplo.proxy.core;
public class Destinatario {
private String nombre;
public Destinatario(String nombre) {
this.nombre = nombre;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
}
3. Implementación del Gestor de Regalos Real
Esta clase contiene la lógica concreta para enviar los regalos. Es el objeto al que el proxy controlará el acceso.
package com.ejemplo.proxy.core;
public class GestorRegalosReal implements IGestorRegalos {
private Destinatario objetivo;
public GestorRegalosReal(Destinatario objetivo) {
this.objetivo = objetivo;
}
@Override
public void enviarFlores() {
System.out.println("Enviando flores a " + objetivo.getNombre() + "...");
}
@Override
public void enviarMuñecos() {
System.out.println("Enviando un lindo muñeco a " + objetivo.getNombre() + "...");
}
@Override
public void enviarChocolates() {
System.out.println("Enviando deliciosos chocolates a " + objetivo.getNombre() + "...");
}
}
4. Clase Proxy de Regalos
El proxy implementa la misma interfaz que el gestor real. Contiene una referencia al gestor real y puede interceptar o modificar las llamadas a sus métodos. En este ejemplo, añade una verificación de acceso antes de cada envío.
package com.ejemplo.proxy.core;
public class ProxyRegalos implements IGestorRegalos {
private GestorRegalosReal gestorReal; // Referencia al objeto real
private Destinatario destinatario; // Necesario para inicializar el objeto real
public ProxyRegalos(Destinatario destinatario) {
this.destinatario = destinatario;
// El objeto real se crea aquí. Para un proxy virtual, se crearía bajo demanda.
this.gestorReal = new GestorRegalosReal(destinatario);
}
// Lógica adicional: una simple verificación de acceso
private boolean verificarAcceso() {
System.out.println("Proxy: Verificando acceso antes de procesar el envío.");
// Aquí podría ir una lógica de seguridad real, registro, etc.
return true; // Simulación de acceso concedido
}
@Override
public void enviarFlores() {
if (verificarAcceso()) {
System.out.println("Proxy: Preparando la delegación de envío de flores.");
gestorReal.enviarFlores();
System.out.println("Proxy: Flores procesadas con éxito.");
} else {
System.out.println("Proxy: Acceso denegado para el envío de flores.");
}
}
@Override
public void enviarMuñecos() {
if (verificarAcceso()) {
System.out.println("Proxy: Preparando la delegación de envío de muñecos.");
gestorReal.enviarMuñecos();
System.out.println("Proxy: Muñecos procesados con éxito.");
} else {
System.out.println("Proxy: Acceso denegado para el envío de muñecos.");
}
}
@Override
public void enviarChocolates() {
if (verificarAcceso()) {
System.out.println("Proxy: Preparando la delegación de envío de chocolates.");
gestorReal.enviarChocolates();
System.out.println("Proxy: Chocolates procesados con éxito.");
} else {
System.out.println("Proxy: Acceso denegado para el envío de chocolates.");
}
}
}
5. Clase de Prueba
Para demostrar el patrón, un cliente interactúa con el proxy. El cliente no necesita saber si está tratando directamente con el objeto real o con un proxy, gracias a la interfaz común.
package com.ejemplo.proxy.test;
import com.ejemplo.proxy.core.Destinatario;
import com.ejemplo.proxy.core.IGestorRegalos;
import com.ejemplo.proxy.core.ProxyRegalos;
public class DemoProxy {
public static void main(String[] args) {
System.out.println("--- Demostración del Patrón Proxy ---");
Destinatario maria = new Destinatario("María");
System.out.println("\nIntentando enviar regalos a " + maria.getNombre() + " a través del proxy:");
// El cliente interactúa con el proxy como si fuera el objeto real
IGestorRegalos proxyParaMaria = new ProxyRegalos(maria);
proxyParaMaria.enviarFlores();
proxyParaMaria.enviarMuñecos();
proxyParaMaria.enviarChocolates();
// Demostración con otro destinatario
Destinatario juan = new Destinatario("Juan");
System.out.println("\n\nIntentando enviar regalos a " + juan.getNombre() + " a través de otro proxy:");
IGestorRegalos proxyParaJuan = new ProxyRegalos(juan);
proxyParaJuan.enviarFlores();
}
}