Patrones de Diseño: Proxy

2 minuto de lectura

El patrón Proxy

El patrón Proxy esta clasificado dentro de los Patrones Estructurales, es también conocido como, Embajador, Apoderado (surrogante). Veamos primero su definición:

Un proxy fuerza a que un método de un objeto RealSubject sea indirectamente ejecutado a través de un objeto Proxy, el cual actúa como delegado o sustituto del objeto RealSubject. Los objetos Proxy son usualmente declarados sin que el Cliente sepa de que se trata de un Objeto Proxy.

Les dejo un diagrama de clases de cómo se implementa este patrón.

Diagrama de Clases - Patrón Proxy

Usos del patrón Proxy

  • Control de Acceso: El patrón puede ser usado para controlar el acceso a los métodos del RealSubject. La lógica del control de acceso se delegará en el proxy, de esta forma quedará mas limpio el RealSubject (en términos de código).
  • Acceso a objetos remotos: Representación de un objeto remoto de forma local, es decir, el Proxy resuelve y enmascara la forma en cómo conectarse al objeto remoto. Ejemplos de implementación de este patrón los pueden encontrar en EJB y RMI.
  • Proxy Virtual: Crea objetos costosos bajo demanda. Por ejemplo, al iniciar una aplicación se pueden instanciar con este patrón todos los iconos de dicha aplicación, pero sólo cuando éste sea solicitado realmente ira a buscarlo al disco y presentado al usuario.
  • Proxy de Referencia Inteligente: Sustituto de una referencia que hace operaciones adicionales cuando se accede a un objeto, como por ejemplo, controlar concurrencia, contar numero de instancias, cargar un objeto en memoria, manejo de cache)

Implementación de Ejemplo

Partamos con la interfaz que deben cumplir tanto RealSubject como el SubjectProxy

public interface Subject {

  void doOperation(String username);

}

Veamos la implementación del RealSubject

public class SubjectReal implements Subject {

  @Override
  public void doOperation(String username) {
    System.out.println("doOperation Real");
  }

}

Finalmente la implementación del SubjectProxy

public class SubjectProxy implements Subject {

  private final Subject _subjectReal;

  private boolean _connected = false;

  public SubjectProxy() {
    _subjectReal = new SubjectReal();
  }

  @Override
  public void doOperation(String username) {
    // Control de Acceso simple
    if (!username.isEmpty() && "admin".equals(username)) {
      System.out.println("doOperacion proxied");
      if (_connected) {
        _subjectReal.doOperation(username);
      } else {
        connectToRemote();
        _subjectReal.doOperation(username);
      }
    } else {
      System.out.println("Access Denied");
    }
  }

  private void connectToRemote() {
    System.out.println("Connecting to remote");
    _connected = true;
  }
}

Nuestro cliente (quien consumirá a Subject) será un test unitario:

public class SubjectTest {

  @Test
  public void testSubjectSimpleUser() {
    Subject subjectProxied = new SubjectProxy();
    subjectProxied.doOperation("user");
  }
}

Esto imprimirá lo siguiente en la consola (systemOut)

Access Denied

La explicación al Access Denied esta dada porque el patrón Proxy se utilizó como control de acceso al método doOperation. Sólo si el username es admin se ejecutará dicho método.

Veamos un Segundo Test Unitario

public class SubjectTest {

  @Test
  public void testSubjectAdmin() {
    Subject subjectProxied = new SubjectProxy();
    subjectProxied.doOperation("admin");
    subjectProxied.doOperation("admin");
  }
}

Esta es la salida:

doOperacion proxied
Connecting to remote
doOperation Real
doOperacion proxied
doOperation Real

En este caso, el usuario admin puede ejecutar la operación y la primera vez que lo haga se conectará un objeto remoto o difícil de crear (simulado para el ejemplo). Luego una vez conectado, podrá ejecutar la operación.

Nuevamente el usuario admin ejecutará la operación por segunda vez y el SubjectProxy ya posee una conexión al objeto remoto, aquí simplemente ejecutará la operación.

Espero les haya gustado y les sirva en sus proyectos, en el siguiente post les comentaré sobre Dynamic Proxy de Java.

Referencias:

Nota: Busquen el error en wikipedia español si lo encuentra me lo comenta ;)

Comentar