Interpreterパターン - PHPパターン
- 公開:
- カテゴリ: PHP DesignPatterns
- タグ: PHP,Behavior,DesignPatterns,Composite,Visitor,Flyweight,Interpreter
Interpreterパターン(インタプリタ・パターン)は、振る舞いに関するデザインパターン手法の1つで、ある機能の「規則」を1つのクラスとして表現し振る舞いを定義する事で、機能拡張を容易にする処理モデルです。
Interpreterパターンの基本的なクラス図は以下の通りです。
実装例
今回は、入力された1行のコマンドを解析し、実行していく流れをInterpreterパターンで実装します。
コマンドが実行されるには、先頭に「$」を、最後に「/」を入力する事を条件とし、それに適合していれば、入力されたコマンドに対応する処理を行います。
まずはContextクラスです。コマンドを保持し、要求に応じてコマンドを返します。
- App/Context/Context.php
-
<?php
namespace App\Context;
class Context
{
private $commands;
private $index = 0;
public function __construct($command)
{
$this->commands = explode(' ', trim($command));
}
public function next()
{
$this->index++;
return $this;
}
public function getCommand()
{
if (!array_key_exists($this->index, $this->commands)) {
return null;
}
return $this->commands[$this->index];
}
}
- コンストラクタで、受け取ったコマンドを解析し配列としてメンバ変数へ格納します。
- getCommand() コマンドで、現在のポインタ(インデックス)にあるコマンドを返却します。
- next() コマンドで、ポインタを次へ進めています。
次はExpressionクラスです。抽象クラスとしてインターフェイスを定義します。
- App/Expression/Interfaces/ExpressionInterface.php
-
<?php
namespace App\Expression\Interfaces;
use App\Context\Context;
interface ExpressionInterface
{
public function execute(Context $context);
}
Expressionの具象クラスでは、execute()メソッドにてContextオブジェクトを受け取り処理を行うという流れになります。
最後にExpressionの具象クラス群です。
- App/Expression/JobExpression.php
-
<?php
namespace App\Expression;
use App\Expression\Interfaces\ExpressionInterface;
use App\Context\Context;
use App\Expression\CommandExpression;
class JobExpression implements ExpressionInterface
{
public function execute(Context $context)
{
if ($context->getCommand() !== '$') {
throw new Exception('Missing opening tag "$"');
}
$command_list = new CommandExpression();
$command_list->execute($context->next());
}
}
JobExpressionクラスは、コマンドのルールである先頭の「$」があるかどうかを評価します。コマンドとしての条件に合致すれば、処理をCommandExpressionクラスへ委譲します。
- App/Expression/CommandExpression.php
-
<?php
namespace App\Expression;
use App\Expression\Interfaces\ExpressionInterface;
use App\Context\Context;
class CommandExpression implements ExpressionInterface
{
public function execute(Context $context)
{
while (true) {
$text = $context->getCommand();
if (is_null($text)) {
throw new Exception('There is no closing command "/"');
} else if ($text === '/') {
break;
} else {
$expression = new DatetimeExpression();
$expression->execute($context);
}
$context->next();
}
}
}
CommandExpressionクラスでは、コマンドルールの最後に関しての評価を行います。併せてそれ以外の場合は、実行コマンドをみなし、DatetimeExpressionクラスへ処理を委譲します。
- App/Expression/DatetimeExpression.php
-
<?php
namespace App\Expression;
use App\Expression\Interfaces\ExpressionInterface;
use App\Context\Context;
class DatetimeExpression implements ExpressionInterface
{
public function execute(Context $context)
{
$command = $context->getCommand();
switch ($command) {
case 'year':
echo date('Y') . ' ';
break;
case 'month':
echo date('m') . ' ';
break;
case 'day':
echo date('d') . ' ';
break;
case 'time':
echo date('H:i') . ' ';
break;
case 'second':
echo date('s') . ' ';
break;
}
}
}
DatetimeExpressionクラスでは、日時に関する処理を行います。渡されたコマンドに対して、必要な処理を行いますが、今回は簡単に日時を返すものになっています。
全ての実装が完了したのでクライアントから利用してみます。
- index.php
-
<?php
use App\Context\Context;
use App\Expression\JobExpression;
// コマンド
$command = '$ year month day time second /';
$job = new JobExpression();
$job->execute(new Context($command));
結果は以下になります。
コマンドに基づいて処理が実行されたことを確認できました。
まとめ
「Interpreter = 通訳」を意味する通り、ドメイン固有言語やファイルに収録されているものを解析し、それによって処理を行う流れを構築します。
特化言語による処理、つまりはある機能に特化した言語的解釈による機能を実装する事で高速に問題を処理できる場合があります。
構文木を構築し、解析・処理するInterpreterパターン。是非試してみてください。