Composite


V této části si ukážeme návrhový vzor Composite. Cílem tohoto návrhového vzoru je, aby se s kolekcí objektů pracovalo stejným způsobem jako se samotným objektem.

Proč Composite použít

Návrhový vzor Composite je o tom, že se s kolekcí objektů pracuje stejným způsobem jako s jedním objektem. Pro jeho implementaci se objekty většinou skládají do nějaké stromové struktury.

Composite se tedy hodí, když chceme se skupinou objektů pracovat stejně jako s jedním objektem.

Příklad - Grafický objekt

Následující ukázka ukazuje třídu GrafickyObjekt a její podtřídy Kruh a Ctverec. Všechny tyto třídy představují grafický objekt, který může obsahovat jiné grafické objekty. S kolekcí grafických objektů (grafickým objektem skládajícím se z více grafických objektů) můžeme pracovat stejným způsobem jako s jedním grafickým objektem. Přesně tuto vlastnost návrhový vzor Composite představuje.

// třída pro grafický objekt
class GrafickyObjekt {
    static pocet = 0;

    constructor(nazev="Skupina " + GrafickyObjekt.pocet++) {
        // grafický objekt se může skládat z více grafických objektů
        this.potomci = [];
        this.barva = undefined;
        this.nazev = nazev;
    }

    // pomocná metoda pro získání textové reprezentace objektu
    print(buffer, odsazeni) {
        // vložení odsazení
        buffer.push("*".repeat(odsazeni));
        if (odsazeni > 0) buffer.push(" ");
        // vložení barvy objektu
        if (this.barva) buffer.push(`[${this.barva}] `);
        // vložení jména objektu
        buffer.push(this.nazev);
        // vložení nového řádku
        buffer.push("\n");

        // zavolání metody print na všechny potomky
        for (let potomek of this.potomci)
            potomek.print(buffer, odsazeni+1);
    }

    // metoda pro získání textové reprezentace objektu
    toString() {
        const buffer = [];
        // objekty (tedy i pole) se předávají adresou
        // - metoda print pracuje přímo s předaným polem
        this.print(buffer, 0);
        return buffer.join("");
    }
}

class Kruh extends GrafickyObjekt {
    constructor(barva) {
        super("Kruh");
        this.barva = barva;
    }
}

class Ctverec extends GrafickyObjekt {
    constructor(barva) {
        super("Čtverec");
        this.barva = barva;
    }
}


// vytvoření grafického objektu kresba
const kresba = new GrafickyObjekt();
// přidání kruhu a čtverce (grafických objektů) do kresby
kresba.potomci.push(new Kruh("žlutá"));
kresba.potomci.push(new Ctverec("zelená"));

// vytvoření grafického objektu skupina
const skupina = new GrafickyObjekt();
// přidání grafických objektů do skupiny
skupina.potomci.push(new Ctverec("modrá"));
skupina.potomci.push(new Kruh("fialová"));
// přidání skupiny do kresby
kresba.potomci.push(skupina);

// všimněte si, že se všemi grafickými objekty pracujeme stejným způsobem

// vypsání struktury grafického objektu
console.log(kresba.toString());
// vypíše se:
// Skupina 0
// * [žlutá] Kruh
// * [zelená] Čtverec
// * Skupina 1
// ** [modrá] Čtverec
// ** [fialová] Kruh