Javascript実践におけるコマンドモードの詳しい説明

Javascript実践におけるコマンドモードの詳しい説明

意味

リクエストをオブジェクトとしてカプセル化することで、異なるリクエストを持つ他のオブジェクトをパラメーター化したり、リクエストをキューに登録したりログに記録したり、元に戻せる操作をサポートしたりできるようになります。

「コマンド パターン」は「リクエスト」をオブジェクトにカプセル化することで、元に戻す操作をサポートしながら、他のオブジェクトを異なるリクエスト、キュー、またはログを使用してパラメータ化できるようにします。

ここでの「リクエスト」の定義は、フロントエンドでよく言われる「Ajax リクエスト」ではなく、アクションを開始することを意味する「アクション リクエスト」です。たとえば、リモコンを使ってテレビの電源を切るときは、「電源を切って」がリクエストになります。コマンド パターンでは、リクエストをコマンドに抽象化します。このコマンドは再利用可能で、受信者 (テレビ) のみを考慮します。アクションの開始側 (リモコン) は、サポートするコマンドのみを考慮しますが、これらのコマンドが具体的に何を行うかは考慮しません。

構造

コマンド パターンのクラス図は次のとおりです。

このクラス図には、5 つの役割があります。

  • クライアント - 具体的なコマンドとレシーバー (アプリケーション層) を作成します。
  • 呼び出し側 - コマンドの発行者。通常はコマンド オブジェクトを保持し、複数のコマンド オブジェクトを保持できます。
  • レシーバー - コマンド レシーバー。実際にコマンドを実行するオブジェクト。コマンドに必要な対応する機能を実装できる限り、どのクラスでもレシーバーになることができます。
  • コマンド - コマンド インターフェース。
  • ConcreteCommand - コマンド インターフェイスの実装。

レシーバーとインボーカーは結合されておらず、機能拡張が必要な​​場合は新しいコマンドが追加されます。そのため、コマンドモードはオープンクローズ原則に準拠しています。

カスタムショートカットキー

ショートカット キーのカスタマイズは、エディターの最も基本的な機能です。コマンド パターンを使用すると、キーの位置とキー ロジックを切り離す構造を記述できます。

インターフェースコマンド{
    実行():void
}

タイプ Keymap = { [キー:文字列]: コマンド }
クラスホットキー{
    キーマップ: キーマップ = {}

    コンストラクタ(キーマップ: キーマップ) {
        this.keymap = キーマップ
    }

    呼び出し(e: キーボードイベント) {
        定数プレフィックス = e.ctrlKey ? 'ctrl+' : ''
        定数キー = プレフィックス + e.key
        this.dispatch(キー)
    }

    ディスパッチ(キー: 文字列) {
        this.keymap[キー].exec()
    }
}

クラスCopyCommandはCommandを実装します{
    コンストラクタ(クリップボード: 任意) {}
    実行() {}
}

CutCommandクラスはCommandを実装します{
    コンストラクタ(クリップボード: 任意) {}
    実行() {}
}

PasteCommandクラスはCommandを実装します{
    コンストラクタ(クリップボード: 任意) {}
    実行() {}
}

const クリップボード = { データ: '' }
定数キーマップ = {
    'ctrl+x': 新しいCutCommand(クリップボード)、
    'ctrl+c': 新しいCopyCommand(クリップボード)、
    'ctrl+v': 新しい PasteCommand(クリップボード)
}
const hotkey = 新しい Hotkey(キーマップ)

document.onkeydown = (e) => {
    ホットキー.call(e)
}

この場合、ホットキーが呼び出し側で、クリップボードが受信者になります。既存のキーマップを変更する必要がある場合は、既存のキーまたはコマンドを追加または置き換えるだけです。

この書き方はお馴染みだと思いますか?はい、Redux もコマンド モードを適用します。Store は Receiver に相当し、Action は Command に相当し、Dispatch は Invoker に相当します。

元に戻すとやり直し

コマンド パターンに基づいて、元に戻すとやり直しをサポートするように簡単に拡張できます。

インターフェース IPerson {
    moveTo(x: 数値, y: 数値): void
}

クラスPersonはPersonを実装します{
    x = 0
    y = 0

    移動先(x: 数値, y: 数値) {
        this.x = x
        this.y = y
    }
}

インターフェースコマンド{
    実行(): 無効
    元に戻す(): 無効
}

MoveCommandクラスはCommandを実装します{
    前X = 0
    前 = 0

    人: 人

    コンストラクタ(人: Person) {
        this.person = 人
    }

    実行() {
        this.prevX = this.person.x
        this.prevY = this.person.y
        this.person.moveTo(this.prevX++、this.prevY++) は、
    }

    元に戻す(){
        this.person.moveTo(this.prevX, this.prevY)
    }
}


const ezio = 新しい Person()
const moveCommand = 新しい MoveCommand(ezio)
移動コマンド.exec()
コンソールログ(ezio.x、ezio.y)
移動コマンド.undo()
コンソールログ(ezio.x、ezio.y)

録音と再生

ゲーム内の録画と再生機能について考えてみましょう。キャラクターの各アクションをコマンドと見なすと、録画中に一連のコマンド キューを取得できます。

クラスコントロール{
    コマンド: コマンド[] = []
    
    exec(コマンド) {
        this.commands.push(コマンド)
        コマンド.exec(this.person)
    }
}

const ezio = 新しい Person()
const コントロール = 新しいコントロール()
control.exec(新しいMoveCommand(ezio))
control.exec(新しいMoveCommand(ezio))

console.log(コントロールコマンド)

コマンド キューがあれば、複数の元に戻す操作とやり直し操作を簡単に実行し、コマンド履歴を実現できます。現在のコマンド キューのポインターを移動するだけです。

クラスコマンド履歴 {
    コマンド: コマンド[] = []
    
    インデックス = 0
    
    現在のコマンドを取得します(){
        this.commands[index]を返す
    }
    
    コンストラクター(コマンド: Command[]) {
        this.commands = コマンド
    }
    
    やり直し(){
        this.index++
        this.currentCommand.exec()
    }
    
    元に戻す() {
        this.currentCommand.undo()
        this.index--
    }
}

同時に、コマンドをオブジェクトにシリアル化すると、保存や送信に使用できるようになります。このようにして、リモート コンピューターに送信し、ezio の動きをリモート制御する機能を実現できます。

[{
    タイプ: '移動'、
    x: 1,
    y: 1,
}, {
    タイプ: '移動'、
    x: 2,
    y: 2,
}]

マクロ

コマンドに対して簡単な処理を行うことで、既存のコマンドを組み合わせて実行し、マクロコマンドとして使用することができます。

クラスBatchedCommandはCommandを実装します{
    コマンド = []
    
    コンストラクタ(コマンド) {
        this.commands = コマンド
    }
    
    実行() {
        this.commands.forEach(コマンド => command.exec())
    }
}

const batchedMoveCommand = 新しいBatchedCommand([
    新しいMoveCommand(ezio)、
    新しいSitCommand(ezio)、
])

バッチ化されたMoveCommand.exec()

要約する

上記の例から、コマンド モードには次の特性があることがわかります。

  • 低結合により、受信者と発信者間の結合が完全に排除されます。
  • 拡張が容易で、新しいコマンドを追加するだけで新しい機能を拡張できます。
  • シリアル化をサポートし、保存と転送が容易になります。
  • これにより、コマンド クラスが簡単に大きくなる可能性があります。

以上がJavascript実践におけるコマンドモードの詳細な説明です。Javascriptコマンドモードの詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • メンテナンス可能なオブジェクト指向 JavaScript コードの作成
  • JavaScript を使用してメンテナンス可能なスライドショー コードを作成する
  • JavaScriptのURLオブジェクトとは何かについて話しましょう
  • JavaScript における正規表現の実際的な応用の詳細な説明
  • JavaScript で配列遅延評価ライブラリを実装する方法
  • 独自のネイティブ JavaScript ルーターを作成する方法
  • JavaScript でアルゴリズムの複雑さを学ぶ方法
  • いくつかの面接の質問を使ってJavaScriptの実行メカニズムを調べる
  • メンテナンス可能なJSコードの書き方を教えます

<<:  一般的な MySQL ストレージ エンジンとパラメータ設定およびチューニングの紹介

>>:  Dockerデータボリューム操作の実装

推薦する

SSHのssh-keygenコマンドの基本的な使い方の詳細な説明

SSH 公開鍵認証は、SSH 認証方式の 1 つです。 SSH パスワードフリーのログインは公開鍵認...

Windows で Mysql を起動したときに 1067 が表示される場合の解決策

数日前に仕事を始めて、Mysql をインストールしたところ、開くことができました。今日、会社に行った...

node_modulesを削除して再インストールする方法

目次ステップ1: プロジェクトをインストールするディレクトリにnode_modulesをインストール...

VMWare 仮想マシン 15.X LAN ネットワーク構成チュートリアル図

最近、分散型およびビッグデータ技術について学ぶために、いくつかの仮想マシンに取り組んでいます。まず、...

HTML 基本コントロール入門_PowerNode Java アカデミー

<input> タグ<input> タグはユーザー情報を収集するために使用さ...

Nginx で Basic Auth ログイン認証を設定する方法

nginx でファイルサーバーを構築することもありますが、これは一般に公開されていますが、サーバーが...

React 非親子コンポーネントパラメータ渡しのサンプルコード

React は、ユーザー インターフェイスを構築するための JavaScript ライブラリです。 ...

MySQL における TIMESTAMPDIFF ケースの詳細な説明

1.構文TIMESTAMPDIFF(unit,begin,end); 単位に従って時間差を返します。...

Node+socketでシンプルなチャットルーム機能を実現

この記事では、参考までに、シンプルなチャットルームを実装するためのnode+socketの具体的なコ...

MySQL の主キーとトランザクションの詳細な説明

目次1. MySQLの主キーとテーブルフィールドに関するコメント1. 主キーと自動増分2. テーブル...

フィルターを使用して画像に透明な CSS を書く方法

フィルターを使用して画像に透明な CSS を書く方法コードをコピーコードは次のとおりです。 html...

Vue での mixin の応用について議論する

Mixin は、再利用可能な機能を Vue コンポーネント間で分散する非常に柔軟な方法を提供します。...

TypeScript 列挙の基本と例

目次序文TypeScript の列挙型とは何ですか? TypeScriptで列挙型を使用する際に注意...

画面なしで無線ネットワークに接続しているときに Raspberry Pi の IP アドレスを見つける方法

あなたがlinuxerだと仮定すると、 windowserだとは想定しません。Windows ユーザ...

MySQL はどのようにしてデータの整合性を確保するのでしょうか?

オンライン ビジネスにとってデータの一貫性と整合性が重要であることは明らかです。データが失われないよ...