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 i en fungerande kodbas. Du behöver en adapter.
Lösning
En Adapter är ett objekt som 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 — det inlindade objektet vet inte om att adaptern finns.
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 (t.ex. tredjepartsbibliotek). |
| Adapter | Implementerar klientgränssnittet och lindar in Service-objektet. |
Exempel — XML till JSON (Java)
Scenariot: Din app producerar data i XML. Analysbiblioteket kräver JSON. Adaptern konverterar formatet transparent.
// ── Klientgränssnitt (din app förstår XML) ────────────────
public interface XmlDataSource {
String fetchXml();
}
// ── Befintlig klass som producerar XML ────────────────────
public class MarketDataService implements XmlDataSource {
@Override
public String fetchXml() {
return "<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) {
System.out.println("Analyserar JSON-data: " + json);
// Komplex analyslogik som bara förstår JSON...
}
}
// ── Adapter: konverterar XML → JSON ───────────────────────
public class XmlToJsonAdapter {
private XmlDataSource xmlSource;
private AnalyticsLibrary analytics;
public XmlToJsonAdapter(XmlDataSource xmlSource) {
this.xmlSource = xmlSource;
this.analytics = new AnalyticsLibrary();
}
public void analyzeData() {
String xml = xmlSource.fetchXml();
String json = convertXmlToJson(xml);
analytics.analyze(json);
}
private String convertXmlToJson(String xml) {
// Förenklad konvertering för demonstration
String symbol = extractTag(xml, "symbol");
String price = extractTag(xml, "price");
String volume = extractTag(xml, "volume");
String json = String.format(
"{\"symbol\":\"%s\",\"price\":%s,\"volume\":%s}",
symbol, price, volume
);
System.out.println("XML in: " + xml);
System.out.println("JSON ut: " + json);
return json;
}
private String extractTag(String xml, String tag) {
int start = xml.indexOf("<" + tag + ">") + tag.length() + 2;
int end = xml.indexOf("</" + tag + ">");
return xml.substring(start, end);
}
}
// ── Klientkod ─────────────────────────────────────────────
public class Application {
public static void main(String[] args) {
XmlDataSource marketData = new MarketDataService();
XmlToJsonAdapter 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.50,"volume":52000000}
Analyserar JSON-data: {"symbol":"AAPL","price":189.50,"volume":52000000}
Fördelar
- Single Responsibility Principle — Konverteringslogiken är isolerad i adaptern.
- Open/Closed Principle — Du kan introducera nya adaptrar utan att ändra klientkoden.
- Du kan återanvända tredjepartsbibliotek som annars är inkompatibla.
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