Facade
Propósito
Proporcionar una interfaz unificada a un conjunto de interfaces de un subsistema. La fachada define una interfaz que
facilita el uso del subsistema.
Explicación
Un ejemplo real
¿Cómo funciona una mina de oro? "¡Bueno, los mineros bajan y sacan oro!" dices. Eso es lo que crees porque estás
usando una interfaz simple que la mina de oro proporciona en el exterior, internamente tiene que hacer un montón de
cosas para que suceda. Esta interfaz simple al subsistema complejo es una fachada.
En pocas palabras
El patrón Facade proporciona una interfaz simplificada a un subsistema complejo.
Wikipedia dice
Una fachada es un objeto que proporciona una interfaz simplificada a un cuerpo de código mayor, como una biblioteca de
clases.
Ejemplo programático
Tomemos el ejemplo de la mina de oro. Aquí tenemos la jerarquía de los trabajadores enanos de la mina. Primero hay una
clase base DwarvenMineWorker
:
@Slf4j
public abstract class DwarvenMineWorker {
public void goToSleep() {
LOGGER.info("{} goes to sleep.", name());
}
public void wakeUp() {
LOGGER.info("{} wakes up.", name());
}
public void goHome() {
LOGGER.info("{} goes home.", name());
}
public void goToMine() {
LOGGER.info("{} goes to the mine.", name());
}
private void action(Action action) {
switch (action) {
case GO_TO_SLEEP -> goToSleep();
case WAKE_UP -> wakeUp();
case GO_HOME -> goHome();
case GO_TO_MINE -> goToMine();
case WORK -> work();
default -> LOGGER.info("Undefined action");
}
}
public void action(Action... actions) {
Arrays.stream(actions).forEach(this::action);
}
public abstract void work();
public abstract String name();
enum Action {
GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK
}
}
Luego tenemos las clases concretas enanas DwarvenTunnelDigger
, DwarvenGoldDigger
y DwarvenCartOperator
:
@Slf4j
public class DwarvenTunnelDigger extends DwarvenMineWorker {
@Override
public void work() {
LOGGER.info("{} creates another promising tunnel.", name());
}
@Override
public String name() {
return "Dwarven tunnel digger";
}
}
@Slf4j
public class DwarvenGoldDigger extends DwarvenMineWorker {
@Override
public void work() {
LOGGER.info("{} digs for gold.", name());
}
@Override
public String name() {
return "Dwarf gold digger";
}
}
@Slf4j
public class DwarvenCartOperator extends DwarvenMineWorker {
@Override
public void work() {
LOGGER.info("{} moves gold chunks out of the mine.", name());
}
@Override
public String name() {
return "Dwarf cart operator";
}
}
Para manejar a todos estos trabajadores de la mina de oro tenemos la FachadaDwarvenGoldmine
:
public class DwarvenGoldmineFacade {
private final List<DwarvenMineWorker> workers;
public DwarvenGoldmineFacade() {
workers = List.of(
new DwarvenGoldDigger(),
new DwarvenCartOperator(),
new DwarvenTunnelDigger());
}
public void startNewDay() {
makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE);
}
public void digOutGold() {
makeActions(workers, DwarvenMineWorker.Action.WORK);
}
public void endDay() {
makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP);
}
private static void makeActions(Collection<DwarvenMineWorker> workers,
DwarvenMineWorker.Action... actions) {
workers.forEach(worker -> worker.action(actions));
}
}
Ahora vamos a utilizar la fachada:
var facade = new DwarvenGoldmineFacade();
facade.startNewDay();
facade.digOutGold();
facade.endDay();
Salida del programa:
// Dwarf gold digger wakes up.
// Dwarf gold digger goes to the mine.
// Dwarf cart operator wakes up.
// Dwarf cart operator goes to the mine.
// Dwarven tunnel digger wakes up.
// Dwarven tunnel digger goes to the mine.
// Dwarf gold digger digs for gold.
// Dwarf cart operator moves gold chunks out of the mine.
// Dwarven tunnel digger creates another promising tunnel.
// Dwarf gold digger goes home.
// Dwarf gold digger goes to sleep.
// Dwarf cart operator goes home.
// Dwarf cart operator goes to sleep.
// Dwarven tunnel digger goes home.
// Dwarven tunnel digger goes to sleep.
Diagrama de clases
Aplicabilidad
Utilice el patrón Fachada cuando
- Quieres proporcionar una interfaz sencilla a un subsistema complejo. Los subsistemas a menudo se vuelven más complejos
a medida que evolucionan. La mayoría de los patrones, cuando se aplican, dan como resultado más clases y más pequeñas.
Esto hace que el subsistema sea más reutilizable y más fácil de personalizar, pero también se vuelve más difícil de
usar para los clientes que no necesitan personalizarlo. Una fachada puede proporcionar una simple vista por defecto
del subsistema que es lo suficiente para la mayoría de los clientes. Sólo los clientes que necesiten más
personalización tendrán que mirar más allá de la fachada. - Hay muchas dependencias entre los clientes y las clases de implementación de una abstracción.
Introducir una fachada para desacoplar el subsistema de los clientes y otros subsistemas, promoviendo así
independencia y portabilidad del subsistema. - Quieres estratificar tus subsistemas. Utiliza una fachada para definir un punto de entrada a cada nivel de subsistema.
Si los subsistemas son dependientes, puedes simplificar las dependencias entre ellos haciéndolos que se comuniquen
entre sí únicamente a través de sus fachadas.