Facade (Fasad)
Introduktion
Facade är ett strukturmönster som tillhandahåller ett förenklat gränssnitt till ett bibliotek, ett ramverk eller en komplex uppsättning klasser.
Problem
Tänk dig att du måste få din kod att fungera med ett komplext videokonverteringsramverk. För att konvertera en fil behöver du initiera en VideoFile, hämta rätt codec via CodecFactory, läsa och konvertera bitrate via BitrateReader och mixa om ljudet med AudioMixer — allt i rätt ordning med rätt beroenden.
Affärslogiken i din app blir hårt kopplad till dessa implementationsdetaljer, koden svår att förstå och varje förändring i ramverket riskerar att ha sönder din kod.
Lösning
En Facade erbjuder ett enkelt gränssnitt till det komplexa delsystemet. Den innehåller precis de funktioner klienten bryr sig om och döljer alla rörliga delar bakom en enda, väldefinierad ingångspunkt.
När ska Facade användas?
- När du behöver ett enkelt gränssnitt till ett komplext delsystem.
- När du vill strukturera ett delsystem i lager med tydliga ingångspunkter.
- När du vill minska beroenden mellan flera delsystem.
Struktur
| Roll | Ansvar |
|---|---|
| Facade | Tar emot klientens begäran och koordinerar delsystemet. |
| Subsystem-klasser | Innehåller den faktiska logiken; känner inte till Facade. |
| Klient | Anropar bara Facade — behöver inte känna till delsystemet. |
Exempel — Videokonverterare (TypeScript)
Scenariot: En VideoConversionFacade döljer ett komplext ramverk för videokonvertering. Klienten behöver bara anropa en metod.
// ── Subsystem-klasser ──────────────────────────────────────
class VideoFile {
readonly codecType: string;
constructor(readonly filename: string) {
this.codecType = filename.split('.').pop() ?? '';
}
}
interface Codec {
type: string;
}
class MPEG4CompressionCodec implements Codec { type = 'mp4'; }
class OggCompressionCodec implements Codec { type = 'ogg'; }
class CodecFactory {
static extract(file: VideoFile): Codec {
if (file.codecType === 'mp4') {
console.log('CodecFactory: extracting MPEG4 audio codec...');
return new MPEG4CompressionCodec();
}
console.log('CodecFactory: extracting OGG audio codec...');
return new OggCompressionCodec();
}
}
class BitrateReader {
static read(file: VideoFile, codec: Codec): VideoFile {
console.log('BitrateReader: reading file...');
return file;
}
static convert(buffer: VideoFile, codec: Codec): VideoFile {
console.log('BitrateReader: converting bitrate...');
return buffer;
}
}
class AudioMixer {
fix(result: VideoFile): string {
console.log('AudioMixer: fixing audio...');
return result.filename;
}
}
// ── Facade ────────────────────────────────────────────────
class VideoConversionFacade {
convertVideo(filename: string, format: string): string {
console.log('\nVideoConversionFacade: starting conversion...');
const file = new VideoFile(filename);
const sourceCodec = CodecFactory.extract(file);
const destinationCodec: Codec =
format === 'mp4' ? new MPEG4CompressionCodec() : new OggCompressionCodec();
const buffer = BitrateReader.read(file, sourceCodec);
const intermediate = BitrateReader.convert(buffer, destinationCodec);
const result = new AudioMixer().fix(intermediate);
console.log('VideoConversionFacade: conversion completed.');
return result;
}
}
// ── Klientkod ─────────────────────────────────────────────
const converter = new VideoConversionFacade();
// Klienten anropar bara EN metod — delsystemets komplexitet är dold
const mp4 = converter.convertVideo('funny-cats.ogg', 'mp4');
console.log('Output:', mp4);
Fördelar
- Isolerar din kod från ett komplext delsystem.
- Reducerar antalet beroenden mellan klienten och delsystemet.
- Lättare att byta ut delsystemet utan att påverka klientkoden.
Nackdelar
- En Facade kan riskera att bli ett “God Object” — kopplad till för många klasser.
Av Victor Hernandez från Bytebase.se