『Java言語で学ぶデザインパターン入門』をPHPで実習する 第3章Template Method

増補改訂版Java言語で学ぶデザインパターン入門

本記事に掲載したサンプルコードは、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」と呼ぶ、ということも合わせて覚えておくと、他の開発者とのコミュニケーションがスムーズになるでしょう。

コメントを残す

コメントを残す