Facade (patrón de deseño)
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.
Índice |
Propósito [editar]
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]
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]
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]
A estrutura corresponde coa seguinte imaxe:
Participantes [editar]
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]
- 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]
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]
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]
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]
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]
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]
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(); } }