Kihagyás

Facade (Homlokzat)

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

Lényege és célja

A Facade minta célja, hogy egy komplex, sok osztályból álló alrendszer (subsystem) elé egy egyszerű, letisztult, és egységes interfészt (homlokzatot) húzzon fel.

Ahelyett, hogy a kliens kódnak ismernie kellene a motorháztető alatt lévő összes apró alkatrészt és azok helyes hívási sorrendjét, a kliens csak a Facade-del kommunikál. A Facade fogadja az egyszerű kéréseket, majd a háttérben "levezényli" a bonyolult műveletsort.

Analógia a való életből

Gondolj egy éttermi rendelésre! Te (a kliens) csak a pincérrel (a Facade) beszélsz. Azt mondod: "Kérek egy sajtburgert menüben". Nem kell lemenned a konyhába a szakácshoz, nem kell szólnod a raktárosnak a krumpliért, és nem kell elmagyaráznod a kasszásnak, hogyan blokkolja be. A pincér az egyetlen belépési pontod, aki elintézi a komplex alrendszerek (konyha, raktár, kassza) összehangolását.

Mikor használjuk?

  • Amikor egy nagyon komplex vagy rosszul megírt (legacy) alrendszert kell használnunk, és el akarjuk rejteni annak bonyolultságát a saját letisztult kliens kódunk elől.
  • Amikor csökkenteni akarjuk a csatolást (coupling) a kliens és az alrendszer osztályai között. Ha a háttérben megváltozik egy alrendszer logikája, elég csak a Facade osztályt frissíteni, a kliens kód érintetlen marad.
  • Amikor a rendszert rétegekre (layers) akarjuk bontani, és minden rétegnek csak a saját Facade-ján keresztül adunk hozzáférést a többi réteghez.

Mermaid Diagram

A diagramon jól látható, hogy a kliens (Main) mentesül a függőségektől: nem kell ismernie sem a TV-t, sem a lámpákat, sem a klímát. Csak a SmartHomeFacade-ot ismeri, ami "HAS-A" (kompozíció) kapcsolatban áll az alrendszerekkel.

classDiagram
    class Client

    class SmartHomeFacade {
        -tv: Tv
        -lights: Lights
        -airConditioner: AirConditioner
        +SmartHomeFacade(ac, tv, lights)
        +startMovieMode() void
        +stopMovieMode() void
    }

    %% Alrendszerek
    class Tv {
        +turnOn() void
        +turnOff() void
    }

    class Lights {
        +dim() void
        +brighten() void
    }

    class AirConditioner {
        +setTemperature(degrees: int) void
        +turnOff() void
    }

    Client --> SmartHomeFacade : "csak ezt használja"

    SmartHomeFacade --> Tv : "vezérli"
    SmartHomeFacade --> Lights : "vezérli"
    SmartHomeFacade --> AirConditioner : "vezérli"

    note for Client "Egy gombnyomás a kliensnél\nkomplex logikát indít el a háttérben."

Forráskód

package structural.facade;

class Tv {

    void turnOn() {
        System.out.println("Tv bekapcsolva.");
    }

    void turnOff() {
        System.out.println("Tv kikapcsolva");
    }
}

class Lights {
    void dim() {
        System.out.println("Fények halványítva");
    }

    void brighten() {
        System.out.println("Fények fényesítve");
    }
}

class AirConditioner {
    void setTemperature(int degrees) {
        System.out.printf("Hőmérséklet beállítva: %s\n", degrees);
    }

    void turnOff() {
        System.out.println("Légkondi kikapcsolva");
    }
}

class SmartHomeFacade {
    private final AirConditioner airConditioner;
    private final Tv tv;
    private final Lights lights;

    SmartHomeFacade(AirConditioner airConditioner, Tv tv, Lights lights) {
        this.airConditioner = airConditioner;
        this.tv = tv;
        this.lights = lights;
    }

    void startMovieMode() {
        tv.turnOn();
        lights.dim();
        airConditioner.setTemperature(22);
    }

    void stopMovieMode() {
        tv.turnOff();
        lights.brighten();
        airConditioner.turnOff();
    }
}

class Main {
    static void main() {
        var smartHomeFacade = new SmartHomeFacade(
                new AirConditioner(),
                new Tv(),
                new Lights()
        );

        smartHomeFacade.startMovieMode();

        System.out.println("After the movie");
        smartHomeFacade.stopMovieMode();
    }
}