Command


V této části si ukážeme návrhový vzor Command. Jedná se v podstatě o objekt, který obsahuje instrukci k vykonání nějaké akce.

Proč Command použít

V kódu často provádíme operace, které nemůžeme vrátit zpět. Když například nějaké proměnné nastavíme novou hodnotu, tak nemůžeme tuto operaci vrátit. Pokud chceme umožnit vrátit zpět nějaké změny, tak můžeme použít návrhový vzor Command. Můžeme si informace o provedených operacích někde ukládat a když je budeme chtít vrátit zpět, tak to díky těmto informacím můžeme udělat.

Command se dá použít k vytvoření undo/redo funkce. Můžeme tedy uživatelům umožnit vrátit jimi provedené změny zpět.

Příklad - Umožnění vrátit operaci zpět

Následující příklad ukazuje třídu BankovniUcet, která představuje bankovní účet a třídu BankovniUcetCommand. Namísto toho, abychom s objektem třídy BankovniUcet manipulovali pomocí jeho metod, vytváříme si objekty třídy BankovniUcetCommand, které obsahují informace o provedených změnách. Díky tomu můžeme provedené operace vrátit zpět.

// třída reprezentující bankovní účet
class BankovniUcet {
    constructor(zustatek = 0) {
        this.zustatek = zustatek;
    }

    vlozit(castka) {
        this.zustatek += castka;
        console.log(`Bylo vloženo ${castka}, zůstatek je nyní ${this.zustatek}.`);
    }

    vybrat(castka) {
        this.zustatek -= castka;
        console.log(`Bylo vybráno ${castka}, zůstatek je nyní ${this.zustatek}.`);
    }

    toString() {
        return `Zůstatek: ${this.zustatek}`;
    }
}

const Akce = Object.freeze({
    vlozit: 0,
    vybrat: 1
});

// Command pro operace s třídou BankovniUcet
class BankovniUcetCommand {
    constructor(ucet, akce, castka) {
        this.ucet = ucet;
        this.akce = akce;
        this.castka = castka;
    }

    // metoda pro provedení příkazu
    proved() {
        switch (this.akce) {
            case Akce.vlozit:
                this.ucet.vlozit(this.castka);
                break;
            case Akce.vybrat:
                this.ucet.vybrat(this.castka);
                break;
        }
    }

    // metoda pro vrácení příkazu zpět
    vratZpet() {
        // provedením opačné operace provedené operace se bankovní účet
        // vrátí do stavu, ve kterém byl před provedením operace
        switch (this.akce) {
            case Akce.vlozit:
                this.ucet.vybrat(this.castka);
                break;
            case Akce.vybrat:
                this.ucet.vlozit(this.castka);
                break;
        }
    }
}


const ucet = new BankovniUcet(50);
console.log(ucet.toString());

// vytvoření příkazu
const cmd = new BankovniUcetCommand(ucet, Akce.vybrat, 15);
// provedení příkazu
cmd.proved();

// vrácení příkazu zpět
cmd.vratZpet();
console.log(ucet.toString());

Třídu BankovniUcetCommand bychom mohli ještě vylepšit. Mohli bychom například přidat vlastnost, která by určovala, jestli se příkaz povedlo provést a tak dále.