本記事に掲載したサンプルコードは、https://github.com/ryo-utsunomiya/design_patternでも公開中です。
Template Methodとは
スーパークラスで処理の枠組を定め、サブクラスでその具体的内容を定めること。
ここでは、「文字・文字列を5回繰り返して表示する」というクラスを実装します。
まずは、表示処理のテンプレートクラス。
<?php
namespace my;
abstract class AbstractDisplay
{
abstract protected function open();
abstract protected function show();
abstract protected function close();
final public function display()
{
$this->open();
for ($i = 0; $i < 5; $i++) {
$this->show();
}
$this->close();
}
}
ここでは、インタフェースではなく、抽象クラスであることが重要です。display()
が処理のテンプレートを定めています(ここでは、open → showを5回繰り返す → close という流れ)。
次に、文字列を表示するクラスを実装します。
<?php
namespace my;
class CharDisplay extends AbstractDisplay
{
/**
* @var string
*/
private $char;
/**
* @param $char
* @throws InvalidArgumentException When $char is not string or longer than 1 character.
*/
public function __construct($char)
{
if (is_string($char) && mb_strlen($char) === 1) {
$this->char = $char[0];
} else {
throw new InvalidArgumentException();
}
}
protected function open()
{
echo '<<';
}
protected function show()
{
echo $this->char;
}
protected function close()
{
echo '>>' . PHP_EOL;
}
}
もう一つは、文字列を表示するクラスです。こちらは文字幅の保時が必要なので、少しだけ複雑です。
<?php
namespace my;
class StringDisplay extends AbstractDisplay
{
/**
* @var string
*/
private $string;
/**
* @var int
*/
private $width;
/**
* @param string $string
* @throws InvalidArgumentException When $char is not string or longer than 1 character.
*/
public function __construct($string)
{
if (is_string($string)) {
$this->string = $string;
$this->width = strlen($string);
} else {
throw new InvalidArgumentException();
}
}
protected function open()
{
$this->printLine();
}
protected function show()
{
echo '|' . $this->string . '|' . PHP_EOL;
}
protected function close()
{
$this->printLine();
}
private function printLine()
{
echo '+';
for ($i = 0; $i < $this->width; $i++) {
echo '-';
}
echo '+' . PHP_EOL;
}
}
以下のようなコードで実行できます。
<?php
namespace my;
require_once __DIR__ . '/../autoload.php';
(new CharDisplay('H'))->display();
(new StringDisplay('Hello, world.'))->display();
出力は以下のようなフォーマットになります。
<<HHHHH>>
+-------------+
|Hello, world.|
|Hello, world.|
|Hello, world.|
|Hello, world.|
|Hello, world.|
+-------------+
このように、「大枠だけ抽象クラスで定義しておいて、個別のクラスの事情に合わせてカスタマイズする」という実装方法はPHPによるWebアプリケーション開発でも頻繁に使うテクニックです。技法としては知っていたという人もおおいでしょうが、この技法を「Template Method」と呼ぶ、ということも合わせて覚えておくと、他の開発者とのコミュニケーションがスムーズになるでしょう。