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

RollAnsvar
KlientArbetar med objekt via klientgränssnittet.
KlientgränssnittBeskriver protokollet som andra klasser måste följa.
ServiceDen användbara klassen med inkompatibelt gränssnitt.
AdapterImplementerar 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.Linq och System.Text.Json gö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