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 (C# / .NET)
Scenariot: En VideoConversionFacade döljer ett komplext ramverk för videokonvertering. Klienten behöver bara anropa en metod.
// ── Subsystem-klasser ──────────────────────────────────────
public class VideoFile
{
public string Filename { get; }
public string CodecType { get; }
public VideoFile(string filename)
{
Filename = filename;
CodecType = Path.GetExtension(filename).TrimStart('.');
}
}
public interface ICodec
{
string Type { get; }
}
public class MPEG4CompressionCodec : ICodec { public string Type => "mp4"; }
public class OggCompressionCodec : ICodec { public string Type => "ogg"; }
public static class CodecFactory
{
public static ICodec Extract(VideoFile file)
{
if (file.CodecType == "mp4")
{
Console.WriteLine("CodecFactory: extracting MPEG4 audio codec...");
return new MPEG4CompressionCodec();
}
Console.WriteLine("CodecFactory: extracting OGG audio codec...");
return new OggCompressionCodec();
}
}
public static class BitrateReader
{
public static VideoFile Read(VideoFile file, ICodec codec)
{
Console.WriteLine("BitrateReader: reading file...");
return file;
}
public static VideoFile Convert(VideoFile buffer, ICodec codec)
{
Console.WriteLine("BitrateReader: converting bitrate...");
return buffer;
}
}
public class AudioMixer
{
public string Fix(VideoFile result)
{
Console.WriteLine("AudioMixer: fixing audio...");
return result.Filename;
}
}
// ── Facade ────────────────────────────────────────────────
public class VideoConversionFacade
{
public string ConvertVideo(string filename, string format)
{
Console.WriteLine("\nVideoConversionFacade: starting conversion...");
VideoFile file = new(filename);
ICodec sourceCodec = CodecFactory.Extract(file);
ICodec destCodec = format == "mp4"
? new MPEG4CompressionCodec()
: new OggCompressionCodec();
VideoFile buffer = BitrateReader.Read(file, sourceCodec);
VideoFile intermediate = BitrateReader.Convert(buffer, destCodec);
string result = new AudioMixer().Fix(intermediate);
Console.WriteLine("VideoConversionFacade: conversion completed.");
return result;
}
}
// ── Klientkod ─────────────────────────────────────────────
VideoConversionFacade converter = new();
// Klienten anropar bara EN metod — delsystemets komplexitet är dold
string mp4 = converter.ConvertVideo("funny-cats.ogg", "mp4");
Console.WriteLine($"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