引用記事
この記事を書くきっかけになったブログです。
記事内の解説やソースコードは、こちらのブログと著者の公開リポジトリを参考にしています。
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();