Bridge


V této části se podíváme na návrhový vzor Bridge. Tento návrhový vzor můžeme použít k propojení různých komponent.

Proč Bridge použít

Bridge spočívá v tom, že při vytváření objektu mu jako vlastnost nastavíme jiný objekt. Objekt tedy bude mít k objektu spojení (odtud název Bridge - Most) a může s ním pracovat.

Díky návrhovému vzoru Bridge nemusíme přidávat funkcionalitu pomocí dědění tříd, ale můžeme třídě jako vlastnost předávat nějaký objekt, který požadovanou funkcionalitu poskytuje.

Příklad - Vykreslování objektů různými renderery

Představme si, že vytváříme nějakou aplikaci, ve které se vykreslují různé geometrické objekty. V této aplikaci chceme objekty vykreslovat dvěma odlišnými způsoby: rastrově a vektorově. Následující ukázka ukazuje, jak bychom mohli vykreslování objektů oběma způsoby umožnit. V ukázce se nachází třída Kruh od které dědí třídy RasterKruh a VectorKruh. Třída RasterKruh slouží pro reprezentaci a vykreslování kruhu rastrovaně a třída VectorKruh vektrově.

class Kruh {
    constructor(x, y, polomer) {
        this.x = x;
        this.y = y;
        this.polomer = polomer;
    }
}

// třída pro kruh, který se má vykreslovat rastrovaně
class RasterKruh extends Kruh {
    constructor(x, y, polomer) {
        super(x, y, polomer);
    }

    // metoda pro vykreslení kruhu rastrovaně
    vykresli() {
        console.log(`Vykresluji RASTROVĚ kruh s poloměrem ${this.polomer}` +
            ` na souřadnicích [${this.x}, ${this.y}].`);
    }
}

// třída pro kruh, který se má vykreslovat vektorově
class VektorKruh extends Kruh {
    constructor(x, y, polomer) {
        super(x, y, polomer);
    }

    // metoda pro vykreslení kruhu vektorově
    vykresli() {
        console.log(`Vykresluji VEKTOROVĚ kruh s poloměrem ${this.polomer}` +
            ` na souřadnicích [${this.x}, ${this.y}].`);
    }
}


const kruh = new RasterKruh(5, 8, 14);
kruh.vykresli();

Pokud nechceme pro každý objekt, který v aplikaci vykreslujeme, vytvářet třídu pro jeho vykreslování rastrovaně a vektorově, tak si pro vykreslování můžeme vytvořit speciální komponentu. Následující ukázka ukazuje třídu RasterRenderer, která slouží pro vykreslování objektů rastrovaně a třídu VectorRenderer, která slouží k vektorovému vykreslování objektů. Namísto dvou tříd pro každý objekt tedy máme jen jednu a při vytváření její instance jen předáváme, který renderer chceme pro vykreslování použít.

// renderer pro rastrové vykreslování objektů
class RasterRenderer {
    vykresliKruh(x, y, polomer) {
        console.log(`Vykresluji RASTROVĚ kruh s poloměrem ${polomer}` +
            ` na souřadnicích [${x}, ${y}].`);
    }
}

// renderer pro vektorové vykreslování objektů
class VectorRenderer {
    vykresliKruh(x, y, polomer) {
        console.log(`Vykresluji VEKTOROVĚ kruh s poloměrem ${polomer}` +
            ` na souřadnicích [${x}, ${y}].`);
    }
}


// základní třída pro všechny tvary, které se v aplikaci vykreslují
class Tvar {
    // zde vlastně Bridge probíhá
    // - odkaz na renderer se uloží jako vlastnost objektu
    constructor(renderer) {
        this.renderer = renderer;
    }
}

class Kruh extends Tvar {
    constructor(renderer, x, y, polomer) {
        super(renderer);
        this.x = x;
        this.y = y;
        this.polomer = polomer;
    }

    vykresli() {
        // o vykreslení kruhu se postará nastavený renderer
        this.renderer.vykresliKruh(this.x, this.y, this.polomer);
    }
}

const renderer = new RasterRenderer();
// při vytváření objektu se předává renderer, který se má použít pro vykreslování
const kruh = new Kruh(renderer, 5, 8, 14);
kruh.vykresli();