CodeForge

Angular 21 de Cero a Experto / Estado a gran escala

El patrón facade: una fachada simple sobre lo complejo

Teoría20 min20 XP

Una feature madura tiene varias piezas por dentro: un store, un servicio de API, quizá lógica de caché o de RxJS. Si cada componente tiene que conocer y coordinar todas esas piezas, se acoplan a los detalles internos. El patrón FACADE resuelve esto: una fachada que expone a los componentes una API SIMPLE —lo que necesitan hacer— ocultando cómo se hace por dentro. Hoy lo dominas y cierras la teoría del módulo.

La recepción del hotel

Un servicio facade

Un facade es un servicio que reúne el store, el API service y la lógica de una feature, y expone solo lo que los componentes necesitan:

bolsillo.facade.ts
import { Injectable, inject } from '@angular/core';
import { BolsilloStore } from './bolsillo.store';
import { ApiGastosService } from './api-gastos.service';

@Injectable({ providedIn: 'root' })
export class BolsilloFacade {
private store = inject(BolsilloStore);
private api = inject(ApiGastosService);

// LECTURAS: reexpone las señales del store (los componentes solo leen)
readonly gastos = this.store.gastos;
readonly total = this.store.total;
readonly saldo = this.store.saldo;
readonly cargando = this.store.cargando;

// ACCIONES: coordinan API + store por dentro
async cargar() {
  this.store.setCargando(true);
  const gastos = await firstValueFrom(this.api.listar());
  this.store.setGastos(gastos);
  this.store.setCargando(false);
}

async agregar(nombre: string, valor: number, categoria: string) {
  const creado = await firstValueFrom(this.api.crear({ nombre, valor, categoria }));
  this.store.agregarLocal(creado);   // actualiza el store tras confirmar el servidor
}
}

El componente ahora solo conoce el facade:

lista.component.ts
@Component({
selector: 'app-lista',
template: `
  <p>Total: {{ bolsillo.total() }} — Saldo: {{ bolsillo.saldo() }}</p>
  @for (g of bolsillo.gastos(); track g.id) { <li>{{ g.nombre }}</li> }
`,
})
export class ListaComponent {
protected bolsillo = inject(BolsilloFacade);   // UNA dependencia, API simple
ngOnInit() { this.bolsillo.cargar(); }
}

El componente no inyecta el store NI el API service directamente: habla solo con el facade. Si mañana cambias cómo se cargan los datos (agregas caché, cambias de API), tocas el facade y NO los componentes. Ese desacople es el valor del patrón.

Cuándo un facade ayuda (y cuándo estorba)

¿Cuál es el principal beneficio de un servicio facade?

Mini-reto

Decide para cada feature si un facade aporta o es sobreingeniería, y justifícalo: 1) "gastos", que coordina un store, un API service con caché y una lógica de invalidación; 2) "tema" (claro/oscuro), que es solo una señal en un servicio; 3) "reportes", que combina datos de gastos con llamadas a una API de análisis y transformaciones. Para las que sí, esboza la API pública del facade (qué lecturas y acciones expondría).

Qué sigue

Cierras la teoría del estado a gran escala: tipos de estado, SignalStore, arquitectura por features y el patrón facade. Tienes el criterio para estructurar una app que vive años. El reto del módulo lo integra: vas a construir un SignalStore de features para "Mi Bolsillo" con estado, derivados y acciones —el store definitivo de tu app—, probado en vivo.