En este nuevo artículo vamos a hablar del patrón proxy, que muchos os imaginaréis su objetivo al recordar el tipo de servidores que lo emplea.
El patrón Proxy proporciona un objeto intermediario entre el cliente y el objeto a utilizar, que permite configurar ciertas características (como el acceso) sin necesidad de modificar la clase original.
Vamos a ver de qué está hecho el patrón Proxy:
Proxy
Nombre: Proxy
Problema y Contexto:
El patrón proxy trata de proporcionar un objeto intermediario que represente o sustituya al objeto original con motivo de controlar el acceso y otras características del mismo.
Se aplica cuando:
El patrón Proxy se usa cuando se necesita una referencia a un objeto más flexible o sofisticada que un puntero. Según la funcionalidad requerida podemos encontrar varias aplicaciones:
- Proxy remoto: representa un objeto en otro espacio de direcciones.
- Proxy virtual: retrasa la creación de objetos costosos.
- Proxy de protección: controla el acceso a un objeto.
- Referencia inteligente: tiene la misma finalidad que un puntero pero además ejecuta acciones adicionales sobre el objeto, como por ejemplo el control de concurrencia.
Solución y Estructura:
La solución a este problema es crear una interfaz Subject que defina toda la funcionalidad que nuestro objeto ha de proveer. Esta interfaz, evidentemente, ha de ser implementada por el objeto real. Crearemos también un Objeto Proxy que mantendrá una referencia al objeto real, y que además implementará la interfaz Subject, de modo que a la hora de precisar la funcionalidad sea indiferente si se está ejecutando el Proxy o el objeto real.
La estructura es la siguiente:
Donde:
Client: precisa de los servicios de Subject aunque trabaja con una referencia Proxy.
Proxy: Mantiene una referencia al objeto real además de implementar la interfaz Subject. El cliente trabajará con este objeto como si fuese el objeto real.
Subject: Interfaz que representa la funcionalidad que tanto el Proxy como el objeto real deben implementar.
RealSubject: Objeto real que implementa la funcionalidad definida por la interfaz Subject.
Consecuencias:
- POSITIVAS: Según el tipo de Proxy, las consecuencias positivas pueden ser:
- Proxy remoto: oculta el hecho de que un objeto reside en otro espacio de direcciones.
- Proxy virtual: puede realizar optimizaciones, como la creación de objetos bajo demanda.
- Proxy de protección y referencias inteligentes: permiten realizar diversas tareas de mantenimiento adicionales al acceder a un objeto.
- NEGATIVAS:
- Introduce un nivel de indirección adicional.
Patrones Relacionados: Adapter y Decorator.
Ejemplo:
Toca clarificar los conceptos mediante un ejemplo. En este caso vamos a hacer un ejemplo clásico de control de acceso mediante un proxy de protección. Para ello vamos a imaginar un escenario en el que se desea realizar la descarga de cierto material que, pese a estar disponible públicamente, no está permitida su posesión en el país del cliente.
En primer lugar definimos la interfaz del servidor de descargas:
public interface Server{
public void download(String url);
}
A continuación vamos a implementar nuestro servidor real:
public class RealServer implements Server{
private int port;
private String host;
public RealServer(int port, String host){
this.port=port;
this.host=host;
System.out.println("Servidor iniciado...");
}
public void download(String url){
System.out.println("Descargando "+host+":"+port+"/"+url);
}
}
Ahora vamos a implementar el proxy que incluye el control de acceso restringido:
public class ProxyServer implements Server{
RealServer srv;
private int port;
private String host;
public ProxyServer(int port, String host){
this.port=port;
this.host=host;
srv=null;
System.out.println("Proxy iniciado...");
}
public void download(String url){
if(!isRestricted(url))
{
if(srv = null)
{
srv = new RealServer(port,host);
}
srv.download(url);
}
else{
System.out.println("Actualmente se encuentra en un área que no permite la descarga del fichero.");
}
}
public boolean isRestricted(String fichero)
{
return !fichero.equals("/descarga/prohibida.avi");
}
}
Puesto que no es relevante para el ejemplo, la implementación del método isRestrictedArea será dummy. Ya tenemos todos los ingredientes, así que vamos a probarlo todo mediante el método main de nuestro cliente:
public static void main(String [] args){
// Creamos el proxy a la página de descargas
Server srv = new ProxyServer(20,"http://paginadedescarg.as");
// Descargamos un archivo permitido
srv.download("/descarga/permitida.avi");
// En este punto será donde se cree el objeto RealServer
// Vamos a probar ahora con una descarga restringida
srv.download("/descarga/prohibida.avi");
}