Facade

A facade egy egyszerűbben használható (vagy egyéb szempontból más) interfészt biztosít egy elfedett osztály, osztály halmaz vagy függvények felé.

Bevezető példa

Tegyük fel, hogy Bluetooth kommunikációt implementálunk egy Bluetooth modul segítségével (pl. Bluegiga WT12). A Bluetooth modult UART-on kereszül tudjuk vezérelni szöveges parancsok segítségével. Péládul a párosításhoz szükséges PIN-t a “SET BT AUTH * 123456” paranccsal tudjuk beállítani.

Objektum orientált alkalmazásunkban egyrészt kényelmes lenne egy objektumon kereszül elérni a szükséges API funkciókat, másrészt egy csomó funkcióra nincs is szükségünk, így számunkra elég lenne egy sokkal egyszerűbb API is, ami egy csomó mindent magától, automatikusan beállít egy default értékre.

A Facade design pattern célja egy olyan interfész kialakítása, mely a mögötte lévő funkciókat az adott alkalmazás számára kényelmesebb formában teszi elérhetővé. Jelen esetben a szükséges funkciókat lefedi a metódusaival, de a feleslegesen bonyolult részleteket elfedi a fejlesztők elől.

class BluetoothCommunication
{
public:
    virtual void SetPin(string pin) = 0;
    virtual std::ostream GetOutputStream() = 0;
    virtual std::istream GetInputStream() = 0;
};

class Wt12Communication : public BluetoothCommunication
{
public:
    virtual void SetPin(string pin) override
    {
        GetOutputStream() << "SET BT AUTH * " << pin << endl;
    }
};

A GetOutputStream() és GetInputStream() metódusokat most nem tárgyaljuk. Lényegük, hogy olyan streameket adnak vissza, amikkel már könnyedén tudunk küldeni/fogadni a bluetooth kapcsolaton keresztül.

A fenti példában később a Wt12Communication osztály segítségével már nagyon könnyen tudunk péládul PIN-t módosítani:

Wt12Communication wt12comm;
wt12comm.SetPin("123456");

Mind a kommunikáció, mind az esetleges visszajelzések és hibaellenőrzések részleteit be tudjuk burkolni a BluetoothCommunication osztály mögé.

Egyéb részletek

A facade tehát belül aggregál egy másik, összetettebb rendszert, vagy interfészt. A facade osztály metódusai ehhez férnek hozzá, hogy megoldják a feladatot, de kifelé egy sokkal egyszerűbb interfészt biztosítanak.

Gyakori alkalmazása, amikor egy viszonylag összetett API-t kell elérni, de a funkciók nagy részére nincsen szükségünk és meg is akarjuk kímélni a fejlesztő csapat többi tagját a felesleges részletektől. Ilyenkor készítünk egy facade osztályt, mely kifelé pont annyit tud, amit kell, a többit meg megoldja belül.

Példa: DLL betöltésének elrejtése

Egyik hallgatómnak szüksége volt egy osztálykönyvtárra, mely C++ alatt lineáris programozási feladatokat tud megoldani. Talált is egy alkalmasat, mely azonban DLL-ben állt rendelkezésre, így a program indulása után a DLL betöltést is meg kellett oldani.

Ilyen esetekben hosszabb távon igen kényelmes, ha ezeket a kiegészítő teendőket elfedjük: készítünk egy facade osztályt, melynek látszólag csak meg kell adni a lineáris programozási feladatot és visszakapjuk az eredményt. A háttérben persze ő betölti a DLL-t, megfelelően inicializálja az osztálykönyvtárat, átadja neki a feladatot, megoldatja, visszaolvassa és esetleg kényelmesebben kezelhető alakra hozza az eredményt, majd visszaadja azt. De ezt kívülről már nem lehet látni és ami még fontosabb, nem is kell tudni róla.

További példák

Szerzők, verziók: Csorba Kristóf