LoginSignup
1
1

More than 5 years have passed since last update.

【PHPデザインパターン】11_Command~要求をクラスで表す

Last updated at Posted at 2019-01-02

引用記事

この記事を書くきっかけになったブログです。

記事内の解説やソースコードは、こちらのブログと著者の公開リポジトリを参考にしています。

Do You PHP はてな〜[doyouphp][phpdp]PHPによるデザインパターン入門 - Command~要求をクラスで表す

概要

  • 「要求」そのものをクラスとして表し、「要求を送る側」と「要求を受け取る側」を分離する。
  • 異なる種類の要求に対する処理を、同じAPIを持つクラスとして実装する。
  • 新しい要求に対する処理クラスを実装するだけで、既存のクラスを修正することなく対応可能である。

構成要素

Commandクラス

  • 命令を実行するためのAPIを定義するクラス。
  • 実行したコマンド結果を保持しておくことで、Undo機能(直前の操作の取り消し)やRedo機能(取り消した操作のやり直し)を実現することができる。

ConcreteCommandクラス

  • Commandクラスのサブクラス。

Invokerクラス

  • 命令実行の要求を出すクラス。

Receiverクラス

  • 命令をどの様に実行するかを知っている唯一のクラス。
  • 任意のクラスがReceiverクラスになれる。

実演

処理の流れ

  • Queueクラスで命令実行の指示を出し、Commandクラスのオブジェクトをセットする。
  • UpperCommandクラスでは、文字列を大文字に変更する。
  • KanaCommandクラスでは、文字列を全角に変更する。
  • 上記2つの実行手順はWordクラスで定義されている。

ファイル構造

MyCommand
  ├── Command.php
  ├── KanaCommand.php
  ├── Queue.php
  ├── UpperCommand.php
  ├── Word.php
  └── my_client.php

ソースコード

Commandクラス

Command.php

Command.php
<?php
namespace DoYouPhp\PhpDesignPattern\Command\MyCommand;

/**
 * Commandクラスに相当する
 * 実装はサブクラスで行う
 */
interface Command
{
    public function execute();
}

ConcreteCommandクラス

UpperCommand.php

UpperCommand.php
<?php
namespace DoYouPhp\PhpDesignPattern\Command\MyCommand;

use DoYouPhp\PhpDesignPattern\Command\MyCommand\Command;
use DoYouPhp\PhpDesignPattern\Command\MyCommand\Word;

/**
 * ConcreteCommandクラスに相当する
 * Commandクラスのメソッドを実装する
 * 文字列を大文字に変える命令を実行する
 */
class UpperCommand implements Command
{
    private $word;

    public function __construct(Word $word)
    {
        $this->word = $word;
    }
    public function execute()
    {
        $this->word->convertUpper();
    }
}

KanaCommand.php

KanaCommand.php
<?php
namespace DoYouPhp\PhpDesignPattern\Command\MyCommand;

use DoYouPhp\PhpDesignPattern\Command\MyCommand\Command;
use DoYouPhp\PhpDesignPattern\Command\MyCommand\Word;

/**
 * ConcreteCommandクラスに相当する
 * Commandクラスのメソッドを実装する
 * 文字列を全角に変える命令を実行する
 */
class KanaCommand implements Command
{
    private $word;

    public function __construct(Word $word)
    {
        $this->word = $word;
    }
    public function execute()
    {
        $this->word->convertKana();
    }
}

Invokerクラス

Queue.php

Queue.php
<?php
namespace DoYouPhp\PhpDesignPattern\Command\MyCommand;

use DoYouPhp\PhpDesignPattern\Command\MyCommand\Command;

/**
 * Invokerクラスに相当する
 */
class Queue
{
    // Commandオブジェクトを配列としてセットする
    private $commands;
    // Commandオブジェクトの配列を回すためのカウンタ
    private $current_index;

    public function __construct()
    {
        $this->commands = array();
        $this->current_index = 0;
    }

    // Commandオブジェクトをセットする
    public function addCommand(Command $command)
    {
        $this->commands[] = $command;
    }

    // セットされたCommandオブジェクトを実行する
    public function run()
    {
        // 配列の全ての要素にアクセスする
        while (!is_null($command = $this->next())) {
            $command->execute();
        }
    }

    // 配列を回してオブジェクトをセットする
    private function next()
    {
        // commandsの数が0か、カウンタがcommandsの数を超えたら処理をストップする
        if (count($this->commands) === 0 || count($this->commands) <= $this->current_index) {
            return;
        } else {
            // 初回の$this->current_index++の値は0
            // 1ずつ加算される
            return $this->commands[$this->current_index++];
        }
    }
}

Receiverクラス

Word.php

Word.php
<?php
namespace DoYouPhp\PhpDesignPattern\Command\MyCommand;

/**
 * Receiverクラスに相当する
 */
class Word
{
    private $word_data;

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

    public function getWord()
    {
        return $this->word_data;
    }

    // 文字列を大文字に変えて出力する
    public function convertUpper()
    {
        echo strtoupper($this->word_data).'<br>'."\n";
    }

    // 文字列を全角に変えて出力する
    public function convertKana()
    {
        echo mb_convert_kana($this->word_data, "R").'<br>'."\n";
    }
}

Clientクラス

my_client.php

my_client.php
<?php
namespace DoYouPhp\PhpDesignPattern\Command\MyCommand;

require dirname(dirname(__DIR__)).'/vendor/autoload.php';

use DoYouPhp\PhpDesignPattern\Command\MyCommand\Queue;
use DoYouPhp\PhpDesignPattern\Command\MyCommand\UpperCommand;
use DoYouPhp\PhpDesignPattern\Command\MyCommand\KanaCommand;
use DoYouPhp\PhpDesignPattern\Command\MyCommand\Word;

// 命令を出すクラスのオブジェクト
$queue = new Queue();
// 命令をどのように実行するか知っているクラスのオブジェクト
$word = new Word('test');
// どの命令を実行するかセットする
$queue->addCommand(new UpperCommand($word));
$queue->addCommand(new KanaCommand($word));

// 命令を実行する
$queue->run();
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1