Facade (patrón de deseño)

Na Galipedia, a Wikipedia en galego.

Os patróns de deseño dan unha solución probada e documentada a problemas que adoitan xurdir no desenvolvemento de software. O patrón de deseño Fachada (Facade) é un tipo de patrón estrutural.

Facade UML class diagram.svg

Propósito[editar | editar a fonte]

O patrón fachada porporciona unha interface unificada de alto nivel para un conxunto de interfaces dun subsistema, facendo que este último sexa mais fácil de usar.

Motivación[editar | editar a fonte]

A principal motivación do patrón fachada é a necesidade de estruturar un sistema en subsistemas menos complexos minimizando deste modo, as comunicacións e as dependencias entre eles.

Aplicabilidade[editar | editar a fonte]

Aplicaremos o patrón fachada cando:

  • Queiramos proporcionar unha interface simple para un subsistema complexo. O patrón fachada pode proporcionar unha vista simple do subsistema que resulta adecuado para a maioría dos clientes. Só aqueles que precisen mais personalización necesitarán ir mais alá da fachada.
  • Desacoplar un sistema dos seus clientes e doutros subsistemas, facendoo mais portable, independente e reutilizable, reducindo as dependencias entre estes.
  • Estruturar varios subsistemas en capas sendo as fachadas o punto de entrada en cada nivel.

Estrutura[editar | editar a fonte]

A estrutura corresponde coa seguinte imaxe:

Facade UML class diagram.svg

Participantes[editar | editar a fonte]

Fachada (Facade): coñece qué clases do subsistema son responsables ante unha petición, e delega as peticións dos clientes aos obxetos apropiados do subsistema.

Subclases (ModuleA, ModuleB, ModuleC...): implementan a funcionalidade do subsistema. Realizan o traballo solicitado pola fachada. Non coñecen a existencia da fachada.

Colaboracións[editar | editar a fonte]

  • Os clientes comunicanse co subsistema enviando peticións ao obxeto Fachada, o cal reenvía as peticións aos obxetos apropiados.
  • Os clientes que usan a fachada non teñen que acceder directamente ós obxetos do subsistema, aínda que poderían facelo.

Consecuencias[editar | editar a fonte]

As consecuencias mais importantes da aplicación deste patrón son:

  • Redución do acoplamento entre clientes e subsistemas (conseguindo que os cambios das clases do sistema sexan transparentes aos clientes) e o illamento de cambios na implementación.
  • Oculta aos clientes a complexidade do subsistema, facilitando o seu uso sen impedir o acceso ás clases do subsistema no caso no que sexa necesario.
  • Facilita a división en capas e reduce dependencias de compilación.

Vantaxes[editar | editar a fonte]

A principal vantaxa deste patrón consiste en que para modificar as clases dos subsistemas, só hai que realizar cambios na fachada, e os clientes poden permanecer alleos a elo. Ademais, os clientes non necesitan coñecer as clases que hai tras dela.

Inconvenientes[editar | editar a fonte]

Se varios clientes necesitan acceder a subconxuntos diferentes da funcionalidade que provee o sistema, poderían acabar usando só unha pequena parte da fachada, polo que sería interesante empregar varias fachadas mais específicas en lugar dunha única global.

Patróns relacionados[editar | editar a fonte]

Un dos patróns relacionados co patrón fachada é o Singleton, dado que en determinadas ocasións as fachadas poden ser instancias únicas.

Os GRASP (General Responsibility Assignment Software Patterns) non son patróns de deseño, senón boas prácticas que guían o desarrollador para encontrar os patróns de deseño, que son mais concretos. Un dos patróns GRASP é un controlador que actúa como punto de entrada na capa lóxica, o que se pode comparar perfectamente có uso do patrón fachada.

Usos coñecidos (problemas/solucións)[editar | editar a fonte]

Problema: Un cliente necesita acceder a parte da funcionalidade dun sistema mais complexo.

  • Definir unha interface que permita acceder unicamente a esa funcionalidade.

Problema: Existen grupos de tarefas moi frecuentes para as que se pode crear código mais sinxelo e lexible.

  • Definir unha funcionalidade que agrupe estas tarefas en funcións ou métodos sinxelos e claros.

Problema: Unha biblioteca é difícilmente lexible.

  • Crear un intermediario mais lexible.

Problema: Dependencia entre o código do cliente e a parte interna duna biblioteca.

  • Crear un intermediario e realizar chamadas á biblioteca só ou a través del.

Problema: Necesidade de acceder a un conxunto de APIs que poden ademais ter un deseño ineficiente.

  • Crear unha API intermedia, ben deseñada, que permita acceder á funcionalidade das demais.

Problema: Moitas clases cliente queren usar varias clases servidoras, e deben saber cal é exactamente a que lle proporciona cada servizo. O sistema volveríase moi complexo, porque habería que relacionar todas as clases cliente con todas e cada unha das clases servidoras.

  • Crear unha ou varias clases Fachada, que implementen todolos servizos, de modo que ou todolos clientes utilicen esa única clase, ou cada grupo de clientes use a fachada que mellor se axuste ás suas necesidades.

Java[editar | editar a fonte]

O seguinte exemplo agocha un calendario cunha API complicada detrás dun patrón Facade más amigable. A saída é:

Data: 2011-05-15
15 días despois: 2011-05-30
import java.util.Calendar;
import java.util.Formatter;
import java.util.GregorianCalendar;
 
/** Fachada */
public class FormatoData {
    private GregorianCalendar gcal;
 
    public FormatoData(String isodate_ymd) {
        String[] a = isodate_ymd.split("-");
        gcal = new GregorianCalendar(Integer.parseInt(a[0]), Integer.parseInt(a[1])-1, Integer.parseInt(a[2]));
    }
 
    public void sumarDias(int dias) { 
	gcal.add(Calendar.DAY_OF_MONTH, dias); 
    }
 
    public String toString() { 
	return String.format("%1$tY-%1$tm-%1$td", gcal);
    }
}
 
/** Cliente */
public class Cliente {
    public static void main(String[] args) {  
        FormatoData d = new FormatoData("2011-05-15");   
        System.out.println("Data: "+d);   
        d.sumarDias(15);   
        System.out.println("15 días despois: "+d);
    }
}

Nestoutro exemplo a fachada axuda a acceder comodamente a tódalas funcionalidades dun sistema de préstamo de libros, vídeos e música.

/**
 * O patrón fachada estrutura un entorno de programación e reduce complexidade coa división en subsistemas.
 */
 
/**
 * Coa interface fachada, temos unha simple interface para acceder a clases diferentes.
 */
public class Fachada {
    private LibrariaLibros libros = new LibrariaLibros();
    private LibrariaVideo videos = new LibrariaVideo();
    private LibrariaMusica musica = new LibrariaMusica();
 
    public void buscarLibros() {
        libros.buscarLibros();
    }
 
    public void buscarMusica() {
        musica.buscarMusica();
    }
 
    public void buscarVideo() {
        videos.buscarVideo();
    }
} 
 
public class LibrariaLibros {
 
    public LibrariaLibros() { }
    public void buscarLibros() { /* ... */ }
}
 
public class LibrariaVideo {
 
    public LibrariaVideo() { }
    public void buscarVideo() { /* ... */ }
}
 
public class LibrariaMusica {
 
    public LibrariaMusica() { }
    public void buscarMusica() { /* ... */ }
}
 
public class Cliente {
 
    public static void main(String args[]){
        Fachada fachada = new Fachada();
        fachada.buscarLibros();
        fachada.buscarVideo();
        fachada.buscarMusica();
    }
}