El patrón Proxy brinda un sustituto de un objeto, con el propósito de controlar el acceso, posponer su creación y representación en memoria hasta que realmente se necesite, o realizar acciones adicionales cuando se accede al objeto, como la carga tardía, la validación de permisos y el manejo de referencias remotas.
Podemos verlo como un representante, que hace de intermediario con el objeto real.
Resuelve varios problemas:
La solución que propone este patrón es:
Este patrón es recomendable cuando:
Separación de Responsabilidades: Permite separar las tareas primarias de un objeto de aspectos secundarios (como control de acceso, logging, etc.).
Mejora del Rendimiento: Puede mejorar el rendimiento y la gestión de recursos mediante la carga tardía y la gestión de la conexión.
Seguridad Mejorada: Permite agregar capas adicionales de seguridad.
Retardo en la Respuesta: El uso de un proxy puede introducir cierta demora en las respuestas.
Complejidad Adicional en el Diseño: Agrega una capa adicional de abstracción, lo que puede complicar el diseño y la depuración.
Posible Sobrecarga de Funcionalidad: Un proxy mal diseñado podría terminar haciendo demasiadas cosas, lo que dificultaría su mantenimiento.
Debemos crear un módulo de gestión de imágenes para un sistema que trabaja con imágenes de alta resolución.
Estas imágenes son muy pesadas y su carga desde el disco duro o una fuente remota es costosa, en términos de tiempo y recursos del sistema.
Cargar todas las imágenes de alta resolución en la memoria al iniciar no es eficiente y puede afectar el rendimiento, además es innecesario, ya que solo unas pocas se visualizan a la vez.
Para optimizar la carga y la visualización de imágenes, vamos usar el patrón Proxy. Esto nos permite diferir la carga de la imagen real hasta que sea absolutamente necesario (por ejemplo, cuando el usuario decide ver una en particular). El Proxy actúa como un marcador de posición, cargando la imagen solo cuando se invoca su método display.
Creamos la interfaz Subject (Image) con el método display. La clase SubjectReal, HighResolutionImage es la que procesa la imagen real. Creamos el intermediario ImageProxy que nos va a permitir efectuar la carga tardía.
Codificamos en Java lo que preparamos en el diagrama.
Definimos la Interfaz Imagen (Subject):
interface Image {
void display();
}
Implementamos un RealSubject:
class HighResolutionImage implements Image {
public HighResolutionImage(String imageFilePath) {
// Supongamos que cargar la imagen es una operación costosa
loadFromDisk(imageFilePath);
}
private void loadFromDisk(String path) {
System.out.println("Cargando " + path);
}
public void display() {
System.out.println("Mostrar imagen");
}
}
Creamos la clase Proxy:
class ImageProxy implements Image {
private HighResolutionImage highResImage;
private String imageFilePath;
public ImageProxy(String imageFilePath) {
this.imageFilePath = imageFilePath;
}
public void display() {
if (highResImage == null) {
highResImage = new HighResolutionImage(imageFilePath);
}
highResImage.display();
}
}
El cliente usa el Proxy:
public class ImageViewer {
public static void main(String[] args) {
Image image1 = new ImageProxy("photo1.jpg");
Image image2 = new ImageProxy("photo2.jpg");
// La imagen no se carga en memoria hasta que se llama a este método
image1.display();
}
}
Los participantes que vimos antes son: Subject, RealSubject, Proxy, Client:
El patrón Proxy es una solución eficiente para gestionar recursos costosos como imágenes de alta resolución en un sistema. Al usar un proxy, podemos cargar recursos pesados solo cuando es necesario, mejorando así el rendimiento y la experiencia del usuario.
El Adapter brinda una interfaz diferente para el objeto que adapta, el Proxy en cambio proporciona la misma interfaz.
Tienen implementación parecida pero distinto propósito. Uno agrega responsabilidades, mientras que el otro actúa como intermediario, controlando el acceso por ejemplo.