Adapter
Introduktion
Adapter är ett strukturmönster som låter objekt med inkompatibla gränssnitt samarbeta — som en reseadapter som låter en svensk kontakt fungera i ett amerikanskt eluttag.
Problem
Du bygger en app för börsanalys som laddar ner marknadsdata i XML-format och visar diagram för användaren.
Vid ett tillfälle vill du integrera ett kraftfullt analysbibliotek från tredje part. Men det finns en hake: biblioteket fungerar bara med data i JSON-format.
Du kan inte ändra biblioteket — det är låst kod. Att skriva om din app för att använda JSON istället för XML skulle kräva enorma ändringar. Du behöver en adapter.
Lösning
En Adapter konverterar gränssnittet för ett objekt så att ett annat objekt kan förstå det. Adaptern lindar in Service-objektet och hanterar konverteringen bakom kulisserna.
När ska Adapter användas?
- När du vill använda en befintlig klass men dess gränssnitt inte matchar resten av din kod.
- När du integrerar med tredjepartskod eller äldre system (legacy code) som du inte kan ändra.
- När du vill återanvända befintliga klasser utan att modifiera dem.
Struktur
| Roll | Ansvar |
|---|---|
| Klient | Arbetar med objekt via klientgränssnittet. |
| Klientgränssnitt | Beskriver protokollet som andra klasser måste följa. |
| Service | Den användbara klassen med inkompatibelt gränssnitt. |
| Adapter | Implementerar klientgränssnittet och lindar in Service-objektet. |
Exempel — XML till JSON (C# / .NET)
Scenariot: Din app producerar data i XML. Analysbiblioteket kräver JSON. Adaptern konverterar formatet transparent.
using System.Text.Json;
using System.Xml.Linq;
// ── Klientgränssnitt (din app förstår XML) ────────────────
public interface IXmlDataSource
{
string FetchXml();
}
// ── Befintlig klass som producerar XML ────────────────────
public class MarketDataService : IXmlDataSource
{
public string FetchXml() =>
"<stock><symbol>AAPL</symbol><price>189.50</price><volume>52000000</volume></stock>";
}
// ── Tredjepartsbibliotek som kräver JSON ──────────────────
public class AnalyticsLibrary
{
public void Analyze(string json)
{
Console.WriteLine($"Analyserar JSON-data: {json}");
// Komplex analyslogik som bara förstår JSON...
}
}
// ── Adapter: konverterar XML → JSON ───────────────────────
public class XmlToJsonAdapter(IXmlDataSource xmlSource)
{
private readonly AnalyticsLibrary _analytics = new();
public void AnalyzeData()
{
string xml = xmlSource.FetchXml();
string json = ConvertXmlToJson(xml);
_analytics.Analyze(json);
}
private static string ConvertXmlToJson(string xml)
{
XDocument doc = XDocument.Parse(xml);
StockData data = new()
{
Symbol = doc.Root!.Element("symbol")!.Value,
Price = double.Parse(doc.Root.Element("price")!.Value),
Volume = long.Parse(doc.Root.Element("volume")!.Value),
};
string json = JsonSerializer.Serialize(data);
Console.WriteLine($"XML in: {xml}");
Console.WriteLine($"JSON ut: {json}");
return json;
}
}
// ── Hjälpklass för serialisering ─────────────────────────
public record StockData
{
public string Symbol { get; init; } = string.Empty;
public double Price { get; init; }
public long Volume { get; init; }
}
// ── Klientkod ─────────────────────────────────────────────
MarketDataService marketData = new();
XmlToJsonAdapter adapter = new(marketData);
// Klienten använder adaptern — vet inte om konverteringen
adapter.AnalyzeData();
Output:
XML in: <stock><symbol>AAPL</symbol><price>189.50</price><volume>52000000</volume></stock>
JSON ut: {"Symbol":"AAPL","Price":189.5,"Volume":52000000}
Analyserar JSON-data: {"Symbol":"AAPL","Price":189.5,"Volume":52000000}
Fördelar
- Single Responsibility Principle — Konverteringslogiken är isolerad i adaptern.
- Open/Closed Principle — Nya adaptrar kan läggas till utan att ändra klientkoden.
- .NET:s
System.Xml.LinqochSystem.Text.Jsongör konverteringen robust och typsäker.
Nackdelar
- Kodkomplexiteten ökar — du lägger till nya klasser.
- Ibland är det enklare att bara skriva om Service-klassen om du har tillgång till den.
Av Victor Hernandez från Bytebase.se