Patrones de Diseño (XI): Patrones Estructurales - Facade

Hoy toca revisar el patron Facade o fachada, patrón de uso común que nos hace simplificar la comunicación entre una clase y otra clase compleja u otro subsistema de clases.

La clase cliente quiere utilizar a la clase objetivo para determinadas operaciones, pero la clase destino es muy compleja, por lo que crearemos una fachada que simplifique la interfaz de la clase destino adaptándola y simplificándola para un uso concreto.

Además Facade permite el desacoplamiento entre clientes y sistemas complejos y subsitemas, permitiendo crear una interfaz de uso de varios sistemas para un fin concreto mediante una única interfaz.

Como siempre, vamos a revisar la plantilla y a aclarar todo mediante un ejemplo para conseguir digerir mejor el concepto de fachada:

Facade


Nombre: Facade

Problema y Contexto:

Disponemos de un sistema complejo que, al ser muy flexible, requiere de la configuración de muchos parámetros para conseguir un fin concreto. Por otro lado, nuestro sistema cliente pretende utilizar parte de la funcionalidad que el primer sistema ofrece pero muchas de las operaciones de configuración son siempre las mismas.

Otro problema que trata de solucionar este patrón es el uso de varias interfaces de subsistemas mediante un único punto de acceso.

Se aplica cuando:

  • Nuestro sistema cliente tiene que acceder a parte de la funcionalidad de un sistema complejo.
  • Hay tareas o configuraciones muy frecuentes y es conveniente simplificar el código de uso.
  • Necesitamos hacer que una librería sea más legible.
  • Nuestros sistemas clientes tienen que acceder a varias APIs y queremos simplificar dicho acceso.


Solución y Estructura:

La solución consiste en crear una clase fachada que proporcione la funcionalidad de manera sencilla a nuestro sistema cliente. Dicha clase utilizará la clase compleja o los distintos componentes de los sistemas requeridos y los ofrecerá por medio de operaciones más simples.

La estructura es la siguiente:


http://4.bp.blogspot.com/-W6xz6EFoXxA/VKVX38_E7cI/AAAAAAAACT0/t6AgrjrF4xI/s1600/facade%2Bpattern%2Bin%2BJava.png

Donde:

Client: Representa al sistema que quiere hacer uso de la clase compleja o el conjunto de susbsistemas mediante la fachada.

Facade: Clase fachada que trata de ofrecer la funcionalidad que demanda el cliente mediante una interfaz sencilla donde, internamente, utiliza las clases complejas.

ComplicatedClassX: Conjunto de clases que se necesitan utilizar y a las que se pretende dar un punto de acceso sencillo mediante la fachada.

Consecuencias

  • POSITIVAS:
    • Simplifica el uso de sistemas complejos con tareas redundantes.
    • Oculta al cliente la complejidad real del sistema.
    • Reduce el acoplamiento entre el subsistema y los clientes.
  • NEGATIVAS:
    • Creamos clases para funcionalidad ya existente.


Patrones Relacionados: Singleton, Mediator y Abstract Factory.

Ejemplo:

En nuestro ejemplo ilustraremos el patron Facade mediante un ejemplo muy comun en la vida real: sacar dinero de la cuenta del banco. Para la retirada de fectivo en un cajero automático, se requiere un gran número de operaciones para garantizar la seguridad y la integridad.

En primer lugar vamos a ver los prototipos de las clases (con implementación dummy, ya que no es relevante) que intervienen en el relativo proceso de retirada de efectivo de un cajero automático:


public class Autentificacion{
/* ... */
public boolean leerTarjeta(){}
public String introducirClave(){}
public boolean comprobarClave(String clave){}
public Cuenta obtenerCuenta(){}
public void alFallar(){}
}

public class Cajero{
/* ... */
public int introducirCantidad(){}
public boolean tieneSaldo(int cantidad){}
public int expedirDinero{}
public String imprimirTicket(){}
}

public class Cuenta{
/* ... */
public double comprobarSaldoDisponible(){}
public boolean bloquearCuenta(){}
public boolean desbloquearCuenta{}
public void retirarSaldo(int cantidad){}
public boolean actualizarCuenta(){}
public void alFallar(){}
}


Mediante estas operaciones, el cliente tendría que acceder a 3 subsistemas y realizar una inmensa cantidad de operaciones. Sin embargo, crearemos una fachada para ofrecer una interfaz mucho más amigable:


public class FachadaCajero{
private Autentificacion autentificacion = new Autentificacion();
private Cajero cajero = new Cajero();
private Cuenta cuenta = null;

public void introducirCredenciales(){
boolean tarjeta_correcta = autentificacion.leerTarjeta();
if(tarjeta_correcta){
String clave = autentificacion.introducirClave();
boolean clave_correcta = autentificacion.comprobarClave(clave);
if(clave_correcta){
cuenta = autentificacion.obtenerCuenta();
return;
}
}
autentificacion.alFallar();
}

public void sacarDinero(){
if(cuenta != null){
int cantidad = cajero.introducirCantidad();
int tiene_dinero = cajero.tieneSaldo(cantidad);
if(tiene_dinero){
boolean hay_saldo_suficiente = ((int)cuenta.comprobarSaldoDisponible()) >= cantidad;
if(hay_saldo_suficiente){
cuenta.bloquearCuenta();
cuenta.retirarSaldo(cantidad);
cuenta.actualizarCuenta();
cuenta.desbloquearCuenta();

cajero.expedirDinero();
cajero.imprimirTicket();
}
else{
cuenta.alFallar();
}
}
}
}
}

De esta manera, hemos conseguido que para que un cliente use el cajero, no tenga que realizar todas las operaciones de sus subsistemas. En lugar de ello proporcionamos una interfaz mucho más simple que facilita enormemente su uso:

public static void main(String[] args){
FachadaCajero cajero_automatico = new FachadaCajero();

cajero_automatico.introducirCredenciales();
cajero_automatico.sacarDinero();
}

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP