Detaillierte Erklärung des Befehlsmodus in der Javascript-Praxis

Detaillierte Erklärung des Befehlsmodus in der Javascript-Praxis

Definition

Kapseln Sie eine Anfrage als Objekt ein. Dadurch können Sie andere Objekte mit unterschiedlichen Anfragen parametrisieren, Anfragen in die Warteschlange stellen oder protokollieren und rückgängig zu machende Vorgänge unterstützen.“

Das „Befehlsmuster“ kapselt „Anfragen“ in Objekte, sodass andere Objekte mithilfe unterschiedlicher Anfragen, Warteschlangen oder Protokolle parametrisiert werden können, während gleichzeitig rückgängig zu machende Vorgänge unterstützt werden.

Die Definition von „Anfrage“ ist hier nicht die „Ajax-Anfrage“, die wir oft im Frontend verwenden, sondern eine „Aktionsanfrage“, also das Einleiten einer Aktion. Wenn Sie beispielsweise den Fernseher mit der Fernbedienung ausschalten, ist „Ausschalten“ eine Aufforderung. Im Befehlsmuster abstrahieren wir die Anfrage in einen Befehl, der wiederverwendbar ist und sich nur um seinen Empfänger (den Fernseher) kümmert. Den Initiator der Aktion (die Fernbedienung) interessiert nur, welche Befehle er unterstützt, nicht aber, was diese Befehle konkret bewirken.

Struktur

Das Klassendiagramm des Befehlsmusters sieht wie folgt aus:

In diesem Klassendiagramm sehen wir fünf Rollen:

  • Client - Erstellen Sie konkrete Befehle und Empfänger (Anwendungsschicht).
  • Aufrufer – Der Herausgeber des Befehls, besitzt normalerweise ein Befehlsobjekt und kann mehrere Befehlsobjekte besitzen.
  • Empfänger – Befehlsempfänger, das Objekt, das den Befehl tatsächlich ausführt. Jede Klasse kann Empfänger werden, sofern sie die entsprechenden vom Befehl geforderten Funktionen implementieren kann.
  • Befehl – ​​Befehlsschnittstelle.
  • ConcreteCommand – Implementierung der Befehlsschnittstelle.

Receiver und Invoker sind nicht gekoppelt. Wenn die Funktion erweitert werden muss, wird ein neuer Befehl hinzugefügt. Der Befehlsmodus entspricht daher dem Open-Closed-Prinzip.

Beispiele

Benutzerdefinierte Tastenkombinationen

Das Anpassen von Tastenkombinationen ist die grundlegendste Funktion eines Editors. Durch das Befehlsmuster können wir eine Struktur schreiben, die die Schlüsselposition von der Schlüssellogik entkoppelt.

Schnittstellenbefehl {
    exec():void
}

Typ Keymap = { [Taste:Zeichenfolge]: Befehl }
Klasse Hotkey {
    Tastenbelegung: Tastenbelegung = {}

    Konstruktor(Tastenbelegung: Tastenbelegung) {
        this.keymap = Tastenbelegung
    }

    Aufruf(e: Tastaturereignis) {
        const Präfix = e.ctrlKey ? 'Strg+' : ''
        const key = Präfix + e.key
        this.dispatch(Schlüssel)
    }

    dispatch(Schlüssel: Zeichenfolge) {
        dies.keymap[Schlüssel].exec()
    }
}

Klasse CopyCommand implementiert Command {
    Konstruktor (Zwischenablage: beliebig) {}
    exec() {}
}

Klasse CutCommand implementiert Command {
    Konstruktor (Zwischenablage: beliebig) {}
    exec() {}
}

Klasse PasteCommand implementiert Command {
    Konstruktor (Zwischenablage: beliebig) {}
    exec() {}
}

const Zwischenablage = { Daten: '' }
const keymap = {
    'Strg+x': neuer Ausschneidebefehl (Zwischenablage),
    'Strg+C': neuer Kopierbefehl (Zwischenablage),
    „Strg+V“: neuer Einfügebefehl (Zwischenablage)
}
const hotkey = neuer Hotkey(Tastenbelegung)

document.onkeydown = (e) => {
    hotkey.call(e)
}

In diesem Fall ist der Hotkey der Aufrufer und die Zwischenablage der Empfänger. Wenn wir eine vorhandene Tastenbelegung ändern müssen, müssen wir nur die vorhandene Taste oder den vorhandenen Befehl hinzufügen oder ersetzen.

Kommt Ihnen dieser Schreibstil bekannt vor? Ja, Redux wendet auch den Befehlsmodus an. Store entspricht Receiver, Action entspricht Command und Dispatch entspricht Invoker.

Rückgängig machen und Wiederherstellen

Basierend auf dem Befehlsmuster können wir es problemlos erweitern, um Rückgängigmachen und Wiederherstellen zu unterstützen.

Schnittstelle IPerson {
    moveTo(x: Zahl, y: Zahl): void
}

Klasse Person implementiert Person {
    x = 0
    y = 0

    moveTo(x: Zahl, y: Zahl) {
        dies.x = x
        dies.y = y
    }
}

Schnittstellenbefehl {
    exec(): ungültig
    rückgängig machen(): void
}

Klasse MoveCommand implementiert Command {
    vorherigesX = 0
    vorherigesY = 0

    person: Person

    Konstruktor(Person: Person) {
        diese.Person = Person
    }

    exec() {
        dies.vorherigesX = diese.Person.x
        dies.vorherigesY = diese.Person.y
        diese.Person.moveTo(dieses.vorherigeX++, dieses.vorherigeY++)
    }

    rückgängig machen() {
        diese.Person.moveTo(dieses.vorherigeX, dieses.vorherigeY)
    }
}


const ezio = neue Person()
const Bewegungsbefehl = neuer Bewegungsbefehl(ezio)
moveCommand.exec()
console.log(ezio.x, ezio.y)
moveCommand.undo()
console.log(ezio.x, ezio.y)

Aufnahme und Wiedergabe

Denken Sie an die Aufnahme- und Wiedergabefunktion im Spiel. Wenn jede Aktion des Charakters als Befehl betrachtet wird, können während der Aufnahme eine Reihe von Befehlswarteschlangen abgerufen werden.

Klasse Control {
    Befehle: Befehl[] = []
    
    exec(Befehl) {
        this.commands.push(Befehl)
        command.exec(diese.Person)
    }
}

const ezio = neue Person()
const Steuerung = neue Steuerung()
control.exec(neuer MoveCommand(ezio))
control.exec(neuer MoveCommand(ezio))

Konsole.log(Steuerungsbefehle)

Wenn wir über eine Befehlswarteschlange verfügen, können wir problemlos mehrere Rückgängig- und Wiederherstellungsvorgänge durchführen und einen Befehlsverlauf erstellen. Bewegen Sie einfach den Zeiger der aktuellen Befehlswarteschlange.

Klasse CommandHistory {
    Befehle: Befehl[] = []
    
    Index = 0
    
    erhalte aktuellenBefehl() {
        gib diese Befehle zurück[index]
    }
    
    Konstruktor(Befehle: Befehl[]) {
        this.commands = Befehle
    }
    
    wiederholen() {
        dies.index++
        dies.currentCommand.exec()
    }
    
    rückgängig machen() {
        this.currentCommand.undo()
        dies.index--
    }
}

Wenn wir den Befehl gleichzeitig in ein Objekt serialisieren, kann er zur Speicherung und Übertragung verwendet werden. Auf diese Weise können wir es an den Remotecomputer senden und die Funktion zur Fernsteuerung der Bewegung von Ezio realisieren.

[{
    Typ: "Verschieben",
    x: 1,
    ja: 1,
}, {
    Typ: "Verschieben",
    x: 2,
    und: 2,
}]

Makros

Durch einfache Verarbeitung des Befehls können Sie die vorhandenen Befehle kombinieren und ausführen und sie so in einen Makrobefehl umwandeln.

Klasse BatchedCommand implementiert Command {
    Befehle = []
    
    Konstruktor(Befehle) {
        this.commands = Befehle
    }
    
    exec() {
        dies.commands.forEach(Befehl => Befehl.exec())
    }
}

const batchedMoveCommand = neuer BatchedCommand([
    neuer MoveCommand(ezio),
    neues SitCommand(ezio),
])

batchedMoveCommand.exec()

Zusammenfassen

Anhand der obigen Beispiele können wir erkennen, dass der Befehlsmodus die folgenden Merkmale aufweist:

  • Durch die geringe Kopplung wird die Kopplung zwischen Empfänger und Anrufer vollständig eliminiert.
  • Einfach zu erweitern, neue Funktionen können durch einfaches Hinzufügen neuer Befehle erweitert werden.
  • Unterstützt die Serialisierung und vereinfacht so die Speicherung und Übertragung.
  • Dies kann leicht zu einer großen Befehlsklasse führen.

Oben finden Sie eine ausführliche Erläuterung des Befehlsmodus in der Javascript-Praxis. Weitere Informationen zum Javascript-Befehlsmodus finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Schreiben von wartbarem, objektorientiertem JavaScript-Code
  • Verwenden von JavaScript zum Erstellen von wartbarem Diashow-Code
  • Lassen Sie uns darüber sprechen, was das URL-Objekt von JavaScript ist
  • Detaillierte Erklärung der praktischen Anwendung regulärer Ausdrücke in JavaScript
  • So implementieren Sie eine Array-Lazy-Evaluation-Bibliothek in JavaScript
  • So erstellen Sie Ihren eigenen nativen JavaScript-Router
  • So lernen Sie algorithmische Komplexität mit JavaScript
  • Verwenden Sie einige Interviewfragen, um den Ausführungsmechanismus von JavaScript zu untersuchen
  • Bringen Sie Ihnen bei, wie Sie wartbaren JS-Code schreiben

<<:  Einführung in gängige MySQL-Speicher-Engines sowie Parametereinstellung und -optimierung

>>:  Implementierung von Docker-Datenvolumenoperationen

Artikel empfehlen

Detaillierter Prozess zum Upgrade von gcc (Version 10.2.0) in der CentOS7-Umgebung

Inhaltsverzeichnis Kurze Einleitung 1. Überprüfen...

So verstehen Sie den Unterschied zwischen ref toRef und toRefs in Vue3

Inhaltsverzeichnis 1. Grundlagen 1.Referenz 2. to...

25 neue nützliche Icon-Sets zum Download im Ausland

1. E-Commerce-Symbole 2. Symbol Süßigkeiten 2 3. ...

Prinzip des Linux-Nohup-Befehls und Beispielanalyse

nohup-Befehl Bei der Verwendung von Unix/Linux mö...

WeChat-Applet: benutzerdefinierter TabBar-Schrittdatensatz

Inhaltsverzeichnis 1. Einleitung 2. Passen Sie de...

Fallstricke bei langsamen MySQL-Abfragen

Inhaltsverzeichnis 1. Langsame Abfragekonfigurati...

Vue integriert Tencent Map zur Implementierung der API (mit DEMO)

Inhaltsverzeichnis Hintergrund zum Schreiben Proj...

HTML-Tutorial: Titelattribut und Alt-Attribut

XHTML ist die Grundlage des CSS-Layouts. jb51.net...

Detaillierte Erklärung des Javascript Echarts Luftqualitätskarteneffekts

Wir müssen zunächst die Luftqualitätsdaten mit de...

Was tun, wenn Sie das ursprüngliche Passwort für MySQL auf dem MAC vergessen?

Die Lösung zum Vergessen des ursprünglichen MySQL...

js, um den Zahlungs-Countdown zu realisieren und zur Startseite zurückzukehren

Zahlungs-Countdown, um zur Startseite zurückzukeh...

So starten Sie Tomcat mit jsvc (als normaler Benutzer ausführen)

Einführung in jsvc In der Produktion sollte Tomca...

So stellen Sie mit Docker schnell einen Elasticsearch-Cluster bereit

In diesem Artikel werden Docker Container (orches...

Vue implementiert die vollständige Auswahlfunktion

In diesem Artikelbeispiel wird der spezifische Co...