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 (PHP)

Scenariot: Din app producerar data i XML. Analysbiblioteket kräver JSON. Adaptern konverterar formatet transparent.

<?php

// ── Klientgränssnitt (din app förstår XML) ────────────────

interface XmlDataSource
{
    public function fetchXml(): string;
}

// ── Befintlig klass som producerar XML ────────────────────

class MarketDataService implements XmlDataSource
{
    public function fetchXml(): string
    {
        return '<stock><symbol>AAPL</symbol><price>189.50</price><volume>52000000</volume></stock>';
    }
}

// ── Tredjepartsbibliotek som kräver JSON ──────────────────

class AnalyticsLibrary
{
    public function analyze(string $json): void
    {
        echo "Analyserar JSON-data: $json\n";
        // Komplex analyslogik som bara förstår JSON...
    }
}

// ── Adapter: konverterar XML → JSON ───────────────────────

class XmlToJsonAdapter
{
    private AnalyticsLibrary $analytics;

    public function __construct(private XmlDataSource $xmlSource)
    {
        $this->analytics = new AnalyticsLibrary();
    }

    public function analyzeData(): void
    {
        $xml  = $this->xmlSource->fetchXml();
        $json = $this->convertXmlToJson($xml);
        $this->analytics->analyze($json);
    }

    private function convertXmlToJson(string $xml): string
    {
        $data = simplexml_load_string($xml);

        $array = [
            'symbol' => (string) $data->symbol,
            'price'  => (float)  $data->price,
            'volume' => (int)    $data->volume,
        ];

        $json = json_encode($array);

        echo "XML in:  $xml\n";
        echo "JSON ut: $json\n";

        return $json;
    }
}

// ── Klientkod ─────────────────────────────────────────────

$marketData = new MarketDataService();
$adapter    = new XmlToJsonAdapter($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.
  • PHP:s inbyggda simplexml_load_string och json_encode gör konverteringen elegant.

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