PHP のコマンド パターンの詳細な分析

青灯夜游
リリース: 2023-04-10 10:36:02
転載
2750 人が閲覧しました

前回の記事「PHP のプロトタイプ モードを理解する」では PHP のプロトタイプ モードについて紹介しましたが、この記事では PHP のコマンド モードについて説明します。

PHP のコマンド パターンの詳細な分析

コマンド モードは、アクション モードまたはトランザクション モードとも呼ばれ、多くの教科書では例としてレストランが使用されます。顧客として、私たちは注文の出し手であり、ウェイターはこの注文の受け取り手であり、メニューは実際の注文であり、シェフはこの注文の実行者です。

それでは、このモデルは何を解決するのでしょうか?メニューを変更したい場合は、ウェイターに伝えるだけで、ウェイターがシェフに伝えてくれるという、お客様とシェフのデカップリングを実現しています。それは、呼び出し側と実装側の分離です。

もちろん、多くのデザイン パターンでこれを行うことができますが、コマンド パターンでできることは、コマンド レシーバーに複数のコマンド (ウェイターが注文を出し、飲み物を受け取り、食べ物を提供する) を実装させたり、コマンドを入力させたりすることです。複数の実装者 (ホット クック、コールド クック、メイン コースのシェフ) に中継されます。ここでコマンド パターンが実際に活躍します。 !

Gof クラス図と説明

GoF 定義: 顧客に対してさまざまなリクエストを使用できるように、リクエストをオブジェクトとしてカプセル化します。 ; リクエストのキューイングまたはログ記録、および取り消し可能な操作のサポート

GoF クラス図

PHP のコマンド パターンの詳細な分析

コード実装

class Invoker
{
    public $command;
    
    public function __construct($command)
    {
        $this->command = $command;
    }

    public function exec()
    {
        $this->command->execute();
    }
}
ログイン後にコピー

まず、コマンドの受信者、より適切にはコマンドの要求者を定義します。クラス図におけるこの単語の英語の定義は「supplicant」です。つまり、コマンドを開始して操作します。

abstract class Command
{
    protected $receiver;

    public function __construct(Receiver $receiver)
    {
        $this->receiver = $receiver;
    }

    abstract public function execute();
}

class ConcreteCommand extends Command
{
    public function execute()
    {
        $this->receiver->action();
    }
}
ログイン後にコピー

次のステップはコマンドです。これは「メニュー」です。このコマンドの目的は、実際の実行者が誰であるかを定義することです。

class Receiver
{
    public $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function action()
    {
        echo $this->name . '命令执行了!', PHP_EOL;
    }
}
ログイン後にコピー

テイカー、つまり執行者は、注文を実際に執行する人です。

// 准备执行者
$receiverA = new Receiver('A');

// 准备命令
$command = new ConcreteCommand($receiverA);

// 请求者
$invoker = new Invoker($command);
$invoker->exec();
ログイン後にコピー

クライアントに電話するには、実行者に連絡する必要があります。つまり、優れたシェフがいるレストランを選択し(受信者)、次にメニューである注文を準備し(コマンド)、最後に手渡します。それをウェイター (呼び出し者) に送信します。

  • 実際、このレストランの例は非常に明確です。コマンド パターンの完璧な分析です。
  • 複数の注文を出せる、または複数の注文を与えることができるという約束についてはどうでしょうか。複数のシェフに?心配しないでください。次のコードはこの問題の解決に役立ちます

完全なコード: https://github.com/zhangyue0503/designpatterns-php/blob/master/09.command/ source/command.php

<?php

class Invoker
{
    private $command = [];

    public function setCommand(Command $command)
    {
        $this->command[] = $command;
    }

    public function exec()
    {
        if(count($this->command) > 0){
            foreach ($this->command as $command) {
                $command->execute();
            }
        }
    }

    public function undo()
    {
        if(count($this->command) > 0){
            foreach ($this->command as $command) {
                $command->undo();
            }
        }
    }
}

abstract class Command
{
    protected $receiver;
    protected $state;
    protected $name;

    public function __construct(Receiver $receiver, $name)
    {
        $this->receiver = $receiver;
        $this->name = $name;
    }

    abstract public function execute();
}

class ConcreteCommand extends Command
{
    public function execute()
    {
        if (!$this->state || $this->state == 2) {
            $this->receiver->action();
            $this->state = 1;
        } else {
            echo $this->name . &#39;命令正在执行,无法再次执行了!&#39;, PHP_EOL;
        }

    }
    
    public function undo()
    {
        if ($this->state == 1) {
            $this->receiver->undo();
            $this->state = 2;
        } else {
            echo $this->name . &#39;命令未执行,无法撤销了!&#39;, PHP_EOL;
        }
    }
}

class Receiver
{
    public $name;
    public function __construct($name)
    {
        $this->name = $name;
    }
    public function action()
    {
        echo $this->name . &#39;命令执行了!&#39;, PHP_EOL;
    }
    public function undo()
    {
        echo $this->name . &#39;命令撤销了!&#39;, PHP_EOL;
    }
}

// 准备执行者
$receiverA = new Receiver(&#39;A&#39;);
$receiverB = new Receiver(&#39;B&#39;);
$receiverC = new Receiver(&#39;C&#39;);

// 准备命令
$commandOne = new ConcreteCommand($receiverA, &#39;A&#39;);
$commandTwo = new ConcreteCommand($receiverA, &#39;B&#39;);
$commandThree = new ConcreteCommand($receiverA, &#39;C&#39;);

// 请求者
$invoker = new Invoker();
$invoker->setCommand($commandOne);
$invoker->setCommand($commandTwo);
$invoker->setCommand($commandThree);
$invoker->exec();
$invoker->undo();

// 新加一个单独的执行者,只执行一个命令
$invokerA = new Invoker();
$invokerA->setCommand($commandOne);
$invokerA->exec();

// 命令A已经执行了,再次执行全部的命令执行者,A命令的state判断无法生效
$invoker->exec();
ログイン後にコピー
  • 今回は、一度に複数の注文と複数のシェフの問題を解決し、間違った注文をした場合に元に戻す問題も解決しました
  • コマンド モードでは、操作を呼び出すオブジェクトと、操作の実装方法を知っているオブジェクトが分離されていることがわかります。
  • 複数のコマンドと複数のエグゼキューターのこの実装は、## に似ています。 #combination モード 実装
  • この場合、新しいコマンドを追加してもエグゼキューターやクライアントには影響しません。新しいクライアントが新しいコマンドを必要とする場合、追加する必要があるのはコマンドとリクエスタのみです。修正の必要がある場合でも、それは修正依頼者のみとなります。
  • Laravel フレームワークのイベント スケジューリング機構には、オブザーバー モードに加えてコマンド モードの影もはっきりと見えます

当社の携帯電話工場携帯電話を作るために鋳物工場が必要な場合も、最初に注文を出しますが、この注文は注文とみなしてよいでしょう。この順序で、使用する必要があるアクセサリ、CPU の種類、メモリの種類、プリインストールされているシステムなどを指定します。そして、鋳物工場の労働者はこの注文に従って生産します。このプロセスでは、特定の作業者が注文を実行するのか、それともグループの作業者が実行するのかを気にする必要はなく、インターフェースを担当する人に注文を渡し、あとは携帯電話が届くのを待つだけで済みます。受け入れられるように生産されます! !

https://github.com/zhangyue0503/designpatterns-php/blob/master/09.command/source/command-up.php

SMS 機能が復活しました。ファクトリ モードに加えて、コマンド モードを実装するのが良い方法であることがわかりました。ここでは、まだ SMS インターフェイスとプッシュ インターフェイスを使用していますが、これ以上苦労せずに、コマンド モードを使用して別のインターフェイスを実装してみましょう。もちろん、興味のある友人は SMS の取り消し機能を実装できます。上記のコマンドのキャンセルがどのように実装されるかを考えてください。

SMS 送信クラス図

PHP のコマンド パターンの詳細な分析

https://github.com/zhangyue0503/designpatterns-php/blob/ master/09.command/source/command-message.php

<?php

class SendMsg
{
    private $command = [];

    public function setCommand(Command $command)
    {
        $this->command[] = $command;
    }
    
    public function send($msg)
    {
        foreach ($this->command as $command) {
            $command->execute($msg);
        }
    }
}

abstract class Command
{
    protected $receiver = [];

    public function setReceiver($receiver)
    {
        $this->receiver[] = $receiver;
    }

    abstract public function execute($msg);
}

class SendAliYun extends Command
{
    public function execute($msg)
    {
        foreach ($this->receiver as $receiver) {
            $receiver->action($msg);
        }
    }
}

class SendJiGuang extends Command
{
    public function execute($msg)
    {
        foreach ($this->receiver as $receiver) {
            $receiver->action($msg);
        }
    }
}

class SendAliYunMsg
{
    public function action($msg)
    {
        echo &#39;【阿X云短信】发送:&#39; . $msg, PHP_EOL;
    }
}

class SendAliYunPush
{
    public function action($msg)
    {
        echo &#39;【阿X云推送】发送:&#39; . $msg, PHP_EOL;
    }
}

class SendJiGuangMsg
{
    public function action($msg)
    {
        echo &#39;【极X短信】发送:&#39; . $msg, PHP_EOL;
    }
}

class SendJiGuangPush
{
    public function action($msg)
    {
        echo &#39;【极X推送】发送:&#39; . $msg, PHP_EOL;
    }
}

$aliMsg = new SendAliYunMsg();
$aliPush = new SendAliYunPush();
$jgMsg = new SendJiGuangMsg();
$jgPush = new SendJiGuangPush();

$sendAliYun = new SendAliYun();
$sendAliYun->setReceiver($aliMsg);
$sendAliYun->setReceiver($aliPush);

$sendJiGuang = new SendJiGuang();
$sendAliYun->setReceiver($jgMsg);
$sendAliYun->setReceiver($jgPush);

$sendMsg = new SendMsg();
$sendMsg->setCommand($sendAliYun);
$sendMsg->setCommand($sendJiGuang);

$sendMsg->send(&#39;这次要搞个大活动,快来注册吧!!&#39;);
ログイン後にコピー

Description

  • この例では、依然としてマルチコマンドおよびマルチエグゼキュータ モードです。
  • この例を抽象ファクトリと比較できます。同じ機能が異なるデザイン パターンを使用して実装されていますが、 note さらに、抽象ファクトリはオブジェクトの生成とオブジェクトの返しに重点を置いているのに対し、コマンド モードは動作の選択です
  • コマンド モードはコマンド キューの形成に非常に適していることがわかります。実行を継続します
  • #これにより、受信側はリクエストを拒否するかどうかを決定でき、受信者は実装者としてより多くの発言権を持ちます
#元のアドレス: https://juejin .cn/post/6844903950768930823

著者: ハードコア プロジェクト マネージャー

推奨学習: 「
PHP ビデオ チュートリアル

以上がPHP のコマンド パターンの詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:juejin.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート