【デザインパターンシリーズ22】コマンドパターン例と原理解析

デザインパターンシリーズの概要

デザインパターン 航空券
3つのファクトリーモデル 搭乗口
戦略モード 搭乗口
委任モード 搭乗口
テンプレートメソッドパターン 搭乗口
オブザーバーモード 搭乗口
シングルトンモード 搭乗口
プロトタイプモード 搭乗口
エージェンシーモデル 搭乗口
デコレータモード 搭乗口
アダプターモード 搭乗口
ビルダーモード 搭乗口
責任連鎖モデル 搭乗口
フライウェイトモデル 搭乗口
コンビネーションモード 搭乗口
ファサードパターン 搭乗口
ブリッジモード 搭乗口
中間モデル 搭乗口
イテレーターモード 搭乗口
状態モード 搭乗口
通訳モード 搭乗口
メモモード 搭乗口
コマンドモード 搭乗口
ビジターモード 搭乗口
ソフトウェア設計の7つの原則と設計パターンの要約 搭乗口

序文

この記事では、主にコマンドモードとその設計モードの原理を紹介し、例を挙げて分析します。

コマンドモードとは

コマンドパターン(コマンドパターン)はコマンドのカプセル化であり、各コマンドは操作です。最初に、要求側が操作を実行するための要求を送信し、次に受信側が要求を受信して​​操作を実行します。

コマンドモードは、リクエスターとレシーバーを切り離します。リクエスターは、コマンドの受信方法、コマンドの操作方法、コマンドの実行方法などを気にせずに、コマンドを送信するだけで済みます。

コマンドモードは動作モードです。

なぜコマンドモードが必要なのですか

当社のソフトウェア開発システムでは、通常、ビヘイビアリクエスターと実際のエグゼキューターは緊密に結合された関係にありますが、この場合、キャンセルややり直しなどのビヘイビアーを変更する必要がある場合は、リクエストのみを変更できます。コマンドモードでは、動作リクエスターとエグゼキューターの間に抽象インターフェイスを導入することにより、リクエスターとエグゼキューターを分離します。そのため、動作を変更する必要がある場合は、対応する動作コマンドを追加するだけで済みます。リクエスターのソースコードを変更する必要はまったくありません。

さて、ふりをする時が再びここにあります:話は安いです、あなたにコードを見せてください、最初に非常に簡単な例を見てみましょう。

コマンドモードの例

例を書くための例として、XShellでのLinuxオペレーティングシステムコマンドの実行を見てみましょう。

1.最初に実際の実行コマンドクラスを作成します。

package com.zwx.design.pattern.command;

public class LinuxSystem {
    
    
    public void cd(){
    
    
        System.out.println("已经切换到主目录");
    }

    public void ls(){
    
    
        System.out.println("已经列举出当前目录下所有文件");
    }

    public void restart(){
    
    
        System.out.println("开始重启系统");
    }
}

2.コマンドインターフェイスを作成します(もちろん、抽象的なプログラミングを対象としています。適切な状況では、ステップ3に直接進むことができます)。

package com.zwx.design.pattern.command;

public interface ICommand {
    
    
    void execute();
}

3.上記のLinuxSystemクラスには3つのコマンドがあるため、次に各コマンドのクラスを作成します。これらのクラスは、コマンドの実際の実行者LinuxSystemを処理するために使用されるLinuxSystemオブジェクトを内部的に維持します。

cdコマンドクラス:

package com.zwx.design.pattern.command;

public class CdCommand implements ICommand {
    
    
    private LinuxSystem linuxSystem;

    public CdCommand(LinuxSystem linuxSystem) {
    
    
        this.linuxSystem = linuxSystem;
    }

    @Override
    public void execute() {
    
    
        linuxSystem.cd();
    }
}

lsコマンドクラス:

package com.zwx.design.pattern.command;

public class LsCommand implements ICommand {
    
    
    private LinuxSystem linuxSystem;

    public LsCommand(LinuxSystem linuxSystem) {
    
    
        this.linuxSystem = linuxSystem;
    }

    @Override
    public void execute() {
    
    
        linuxSystem.ls();
    }
}

コマンドクラスを再起動します。

package com.zwx.design.pattern.command;

public class RestartCommand implements ICommand {
    
    
    private LinuxSystem linuxSystem;

    public RestartCommand(LinuxSystem linuxSystem) {
    
    
        this.linuxSystem = linuxSystem;
    }

    @Override
    public void execute() {
    
    
        this.linuxSystem.restart();
    }
}

4.次に、コマンドを受信するためのクラスも必要です。

package com.zwx.design.pattern.command;

import org.omg.PortableServer.LIFESPAN_POLICY_ID;

import java.util.ArrayList;
import java.util.List;

public class XshellInvoker {
    
    
    private List<ICommand> commandList = new ArrayList<>();

    public XshellInvoker(List<ICommand> commandList) {
    
    
        this.commandList = commandList;
    }

    /**
     * 执行指定命令
     * @param command
     */
    public void execute(ICommand command){
    
    
        command.execute();
    }

    /**
     * 执行命令宏
     */
    public void executeCdAndLs(){
    
    
        for (ICommand command : commandList){
    
    
            if (command instanceof LsCommand || command instanceof CdCommand){
    
    
                command.execute();
            }
        }
    }

    public void executeAll(){
    
    
        for (ICommand command : commandList){
    
    
            command.execute();
        }
    }
}

5.最後に、新しいテストクラスを作成しましょう。

package com.zwx.design.pattern.command;

import java.util.ArrayList;
import java.util.List;

public class TestCommand {
    
    

    public static void main(String[] args) {
    
    
        LinuxSystem linuxSystem = new LinuxSystem();
        List<ICommand> commandList = new ArrayList<>();
        commandList.add(new CdCommand(linuxSystem));
        commandList.add(new LsCommand(linuxSystem));
        commandList.add(new RestartCommand(linuxSystem));

        XshellInvoker xshellInvoker = new XshellInvoker(commandList);

        xshellInvoker.execute(new LsCommand(linuxSystem));//执行指定命令
        System.out.println("------------------------");
        xshellInvoker.executeCdAndLs();//指定特定命令宏
        System.out.println("------------------------");
        xshellInvoker.executeAll();//执行全部命令
    }
}

結果は次のとおりです。

已经列举出当前目录下所有文件
------------------------
已经切换到主目录
已经列举出当前目录下所有文件
------------------------
已经切换到主目录
已经列举出当前目录下所有文件
开始重启系统

上記はコマンドモードの標準的な記述方法です。ご覧のとおり、コントローラーはコマンドエグゼキューターから切り離されているため、後で新しいコマンドを拡張し続ける場合は、別のコマンドクラスを追加します。

コマンドモードの役割

上記の例から、イテレーターモードには主に4つの役割があると結論付けることができます。

  • 受信者の役割(受信者):要求の特定の実装または実行を担当します(例のLinuxSystemなど)。
  • コマンドロール(コマンド):実行する必要のあるすべてのコマンドライン(例のICommandなど)を定義します。
  • 特定のコマンドロール(ConcreteCommand):このクラスは、レシーバー(Receiver)を内部的に維持します。実行コマンド要求を受信した後、Receiverの対応するメソッド(例ではCdCommand、LsCommand、RestartCommandなど)が呼び出されます。
  • リクエスター(呼び出し元)の役割:クライアントのコマンドを受信し、対応するコマンドを呼び出します(例のように)。

コマンドモードのアプリケーションシナリオ

実際、コマンドモードの考え方は、仲介者を介してコマンドのリクエスターと実装者を切り離すことです。主に次のシナリオに適用されます。

  • 1. dosコマンドやシェルコマンドなど、現実的なセマンティクスの「コマンド」を使用した操作があります。
  • 2.要求の発信者と受信者は、発信者と受信者が互いに直接電話をかけないように分離する必要があります。
  • 3.元に戻す操作や回復操作など、実行を待機している動作を抽象化する必要があります。
  • 4.コマンドマクロ(つまり、コマンドの組み合わせ)操作をサポートする必要があります。

コマンドモードの長所と短所

利点:

  • 1.ミドルウェア(抽象インターフェース)を導入することにより、要求と実装を切り離します。
  • 2.新しいコマンドを追加してオブジェクトを直接追加するだけで、展開するのに便利です。
  • 3.コマンドの組み合わせ操作をサポートし、より柔軟で便利です。

不利益

  • 1.コマンドが多すぎると、オブジェクトが非常に大きくなります。

総括する

この記事では、主にコマンドモードの基本的な使用法を紹介し、コマンドモードをよりよく理解するために簡単な例を使用します。最後に、コマンドモードを使用することの長所と短所を簡単に要約します。

私に注意を払い、孤独なオオカミを学び、進歩してください

おすすめ

転載: blog.csdn.net/zwx900102/article/details/109352746