Kihagyás

Adapter (Illesztő)

Kategória: Strukturális minta (Structural Pattern)

Lényege és célja

Az Adapter minta célja, hogy két egymással inkompatibilis interfészt összekössön, lehetővé téve olyan osztályok együttműködését, amelyek az eltérő felületeik miatt alapból nem tudnának kommunikálni.

A legtalálóbb analógia a való életből a konnektor-adapter: ha egy amerikai dugót akarsz bedugni egy európai aljzatba, nem a falat bontod le, és nem is a gép kábelét vágod le, hanem beteszel közéjük egy adaptert, ami elvégzi a "fordítást".

A minta három fő szereplője:

  1. Target (Cél): Az az interfész, amit a modern, saját rendszerünk (a kliens) ismer és használni akar (pl. JsonLogger).
  2. Adaptee (Illesztendő): A régi, meglévő osztály (legacy kód vagy külső könyvtár), aminek hasznos a belső logikája, de rossz/elavult az interfésze (pl. LegacyXmlLogger).
  3. Adapter (Illesztő): A "híd" a kettő között. Implementálja a Cél interfészt, és kompozícióval ("HAS-A") tartalmaz egy példányt az Illesztendő osztályból. Amikor a kliens meghívja a modern metódust, az Adapter lefordítja a paramétereket, és továbbhívja a régi rendszer metódusát.

Mikor használjuk?

  • Amikor egy meglévő, régi osztályt kell használnunk, de az interfésze nem illeszkedik a rendszerünk többi részéhez.
  • Amikor egy külső (third-party) könyvtárat integrálunk, és nem akarjuk, hogy a mi üzleti logikánk szorosan rácsatlakozzon az ő kódjukra (Védőréteg / Anti-Corruption Layer építése).
  • Amikor számítunk rá, hogy egy régi rendszert később egy újra cserélünk: ha már a kezdetektől Adaptert használunk, a csere pillanatában csak az Adaptert kell eldobnunk, az üzleti logika érintetlen marad.

Mermaid Diagram

A diagramon látható, ahogy az Adapter megvalósítja az új, JSON alapú interfészt, miközben a háttérben burkolja a régi, XML alapú loggert, átalakítva a hívásokat.

classDiagram
    class JsonLogger {
        <<interface>>
        +logJson(key: String, value: String) void
    }

    class XmlToJsonLoggerAdapter {
        -legacyLogger: LegacyXmlLogger
        +XmlToJsonLoggerAdapter(logger: LegacyXmlLogger)
        +logJson(key: String, value: String) void
    }

    class LegacyXmlLogger {
        +logXml(message: String) void
    }

    class Client

    Client --> JsonLogger : "használja"

    XmlToJsonLoggerAdapter ..|> JsonLogger : "implementálja"

    %% Az Adapter becsomagolja a régi osztályt
    XmlToJsonLoggerAdapter o--> LegacyXmlLogger : "tartalmazza (delegál neki)"

    note for XmlToJsonLoggerAdapter "Formázza a kapott JSON adatot XML-lé,\nmajd meghívja a legacyLogger.logXml()-t"

Forráskód

package structural.adapter;

class LegacyXmlLogger {
    void logXml(String message) {
        System.out.println("<log>" + message + "</log>");
    }
}

interface JsonLogger {
    void logJson(String key, String value);
}

class XmlToJsonLoggerAdapter implements JsonLogger {

    private final LegacyXmlLogger legacyXmlLogger;

    public XmlToJsonLoggerAdapter(LegacyXmlLogger legacyXmlLogger) {
        this.legacyXmlLogger = legacyXmlLogger;
    }

    @Override
    public void logJson(String key, String value) {
        var logMessage = "{ \"" + key + "\" : \"" + value + "\" }";
        legacyXmlLogger.logXml(logMessage);
    }
}

class Main {
    static void main() {
        var legacyXmlLogger = new LegacyXmlLogger();

        JsonLogger xmlToJsonLoggerAdapter = new XmlToJsonLoggerAdapter(legacyXmlLogger);
        xmlToJsonLoggerAdapter.logJson("user", "john_doe");
    }
}