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 (PHP)
Scenariot: En VideoConversionFacade döljer ett komplext ramverk för videokonvertering. Klienten behöver bara anropa en metod.
<?php
// ── Subsystem-klasser ──────────────────────────────────────
class VideoFile
{
public readonly string $codecType;
public function __construct(public readonly string $filename)
{
$this->codecType = pathinfo($filename, PATHINFO_EXTENSION);
}
}
interface Codec
{
public function getType(): string;
}
class MPEG4CompressionCodec implements Codec
{
public function getType(): string { return 'mp4'; }
}
class OggCompressionCodec implements Codec
{
public function getType(): string { return 'ogg'; }
}
class CodecFactory
{
public static function extract(VideoFile $file): Codec
{
if ($file->codecType === 'mp4') {
echo "CodecFactory: extracting MPEG4 audio codec...\n";
return new MPEG4CompressionCodec();
}
echo "CodecFactory: extracting OGG audio codec...\n";
return new OggCompressionCodec();
}
}
class BitrateReader
{
public static function read(VideoFile $file, Codec $codec): VideoFile
{
echo "BitrateReader: reading file...\n";
return $file;
}
public static function convert(VideoFile $buffer, Codec $codec): VideoFile
{
echo "BitrateReader: converting bitrate...\n";
return $buffer;
}
}
class AudioMixer
{
public function fix(VideoFile $result): string
{
echo "AudioMixer: fixing audio...\n";
return $result->filename;
}
}
// ── Facade ────────────────────────────────────────────────
class VideoConversionFacade
{
public function convertVideo(string $filename, string $format): string
{
echo "\nVideoConversionFacade: starting conversion...\n";
$file = new VideoFile($filename);
$sourceCodec = CodecFactory::extract($file);
$destinationCodec = $format === 'mp4'
? new MPEG4CompressionCodec()
: new OggCompressionCodec();
$buffer = BitrateReader::read($file, $sourceCodec);
$intermediate = BitrateReader::convert($buffer, $destinationCodec);
$result = (new AudioMixer())->fix($intermediate);
echo "VideoConversionFacade: conversion completed.\n";
return $result;
}
}
// ── Klientkod ─────────────────────────────────────────────
$converter = new VideoConversionFacade();
// Klienten anropar bara EN metod — delsystemets komplexitet är dold
$mp4 = $converter->convertVideo('funny-cats.ogg', 'mp4');
echo "Output: $mp4\n";
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