Este patrón se basa en proporcionar un objeto que haga de intermediario (proxy) de otro, para controlar el acceso a él.
Existen diferentes tipos de proxy:
- Proxy remoto: proporciona un representante local de un objeto situado en otro espacios de direcciones (en otro dispositivo conectado en red).
- Proxy virtual: usados para crear objetos costosos sólo cuando se soliciten.
- Proxy de protección: permiten controlar el acceso a un objeto cuando es accesible o no, dependiendo de determinados permisos.
- Referencia inteligente: un sustito de un puntero, que realiza operaciones adicionales en el momento de accederse al objeto.
Veamos un ejemplo de Proxy virtual en el que abrimos un documento que contiene una imagen, la cual se cargará y mostrará cuando el usuario haga scroll.
Main.java:
package estructurales.proxy.proxy01;
public class Main
{
public static void main( String[] args )
{
// Abrimos un documento que puede contener una sola imagen
Documento doc = new Documento( "Presupuesto.doc");
try // Necesario al usar Thread
{
// Pausamos la ejecución del programa durante 3 segundos
Thread.sleep( 3000 );
// Simulamos que el usuario hace scroll
doc.hacerScroll();
}
catch( Exception e )
{
System.out.println("Ha ocurrido un error");
}
}
}
Documento.java:
package estructurales.proxy.proxy01;
public class Documento
{
private String nombreDoc;
private String texto;
private ImagenProxy imgProxy;
// ---------------------------
public Documento( String nombreDoc )
{
this.setNombreDoc( nombreDoc );
this.cargarContenido();
this.mostrar();
}
// ---------------------------
public String getNombreDoc()
{
return this.nombreDoc;
}
// ---------------------------
public void setNombreDoc( String nombreDoc )
{
this.nombreDoc = nombreDoc;
}
// ---------------------------
public void cargarContenido()
{
// Aquí cargaríamos el archivo y obtendríamos su contenido
this.texto = "Texto del documento";
this.imgProxy = new ImagenProxy( "imagen.jpg" );
System.out.println("Documento cargado en memoria");
}
// ------------------------
public void mostrar()
{
System.out.println("Mostrando el contenido...\n");
}
// ------------------------
// Supongamos que este método es un evento que se lanza al hacer scroll
public void hacerScroll()
{
System.out.println("El usuario ha hecho scroll...");
imgProxy.mostrarImagen();
}
}
Imagen.java (Sujeto en el diagrama anterior):
package estructurales.proxy.proxy01;
public interface Imagen
{
public void mostrarImagen();
}
ImagenReal.java (SujetoReal en el diagrama anterior):
package estructurales.proxy.proxy01;
public class ImagenReal implements Imagen
{
private String nombre;
// ---------------------------
public ImagenReal( String nombre )
{
this.nombre = nombre;
}
// ---------------------------
@Override
public void mostrarImagen()
{
System.out.println("Mostrando imagen: [" + nombre + "]" );
}
}
ImagenProxy.java (Proxy en el diagrama anterior):
package estructurales.proxy.proxy01;
public class ImagenProxy implements Imagen
{
private ImagenReal imagen = null;
private String nombreImagen = "";
// ---------------------------
public ImagenProxy( String nombreImagen )
{
this.nombreImagen = nombreImagen;
}
// ---------------------------
@Override
public void mostrarImagen()
{
if(this.imagen == null)
{
this.imagen = new ImagenReal( nombreImagen );
}
this.imagen.mostrarImagen();
}
}
Al ejecutarlo obtendríamos como resultado:
EXPLICACIÓN:
- Al inicio del programa cargamos un Documento y transcurridos unos segundos simulamos que el usuario hace scroll en el mismo.
- La clase Documento guarda una referencia a ImageProxy, instanciándose al cargar el documento con el nombre de la imagen que corresponda.
- La clase ImagenProxy guarda una referencia de ImagenReal, devolviendo ésta cuando lo solicite el documento.

Para usar este patrón en lenguaje Java podemos utilizar la interface InvocationHandler.