【PHPデザインパターン】01_TemplateMethod~処理を穴埋めする


引用記事

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

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

Do You PHP はてな〜[doyouphp][phpdp]PHPによるデザインパターン入門 - TemplateMethod~処理を穴埋めする

概要

  • 親クラスで処理の大きな枠組みを定義し、具体的な処理内容をサブクラスで決定させる。
  • 親クラスでは抽象メソッドが定義されている。抽象メソッドとして定義したメソッドは、サブクラスにおける実装が保証されている。
  • 継承を利用する。
  • サブクラスの型は、その親クラスの型と置換可能である。(リスコフの置換原則)
  • 親クラスがサブクラスのメソッドを呼び出す「制御構造の反転」という特長を持つ。(ハリウッドの原則)

構成

  • 親クラスに、サブクラスに固有で持たせたいメソッドを、TemplateMethodとして定義する。
  • TemplateMethod内のメソッドはabstract(抽象クラス)として定義するため、サブクラスにおける定義が必須になる。
  • サブクラスで、abstractとして定義したメソッドをサブクラス固有のメソッドとして定義する。
  • 逆に、TemplateMethod内のメソッドは親クラスでは定義できない。

ソースコード

前回の記事ではオートロードや名前空間を利用していましたが、今回コードを簡素化したため、クラスも1つのファイルにまとめました。
そのため、require_onceでクラスを記述しているファイルを呼び出しています。

処理の詳細は、ファイル内のコメントに記載しました。

処理の流れ

  • 親クラスとしてAbstractDisplayクラスを定義する。
  • サブクラスとしてBreakDisplayクラスTabDisplayクラスを定義する。
  • 配列をプロパティとして受け取り、それを返す処理は、各サブクラスで共通している。
  • BreakDisplayクラスでは、配列の各要素を改行区切りで返す。
  • TabDisplayクラスでは、配列の各要素をタブ区切りで返す。

my_client.php

  • クライアント側のファイルです。
my_client.php
<?php
// クラスが記述されているファイルを読み込む
require_once 'my_class.php';

// 表示する配列を定義する
$data = array('apple', 'orange', 'peach', 'banana');

// BreakDisplayクラスのインスタンスを作成
// displayメソッドを呼び出す
$display = new BreakDisplay($data);
$display->display();

echo str_repeat('-', 40)."<br>"."\n";

// TabDisplayクラスのインスタンスを作成
// displayメソッドを呼び出す
$display = new TabDisplay($data);
$display->display();

my_class.php

  • 親クラス、サブクラスが定義されているファイルです。
my_class.php
<?php
// 抽象クラスとして作成
// そのためAbstractDisplayのインスタンスは作成できない
abstract class AbstractDisplay
{
    // プロパティ(メンバ変数)の定義
    // privateで定義されていてもgetDataメソッドでサブクラスから呼び出せる
    private $data;

    // オブジェクト生成時にコールされるメソッド
    // オブジェクトを使用する前に必要な初期化を行う
    public function __construct($data)
    {
        if (!is_array($data)) {
            $data = array($data);
        }

        $this->data = $data;
    }

    // サブクラスで共通して使用するメソッド
    public function getData()
    {
        return $this->data;
    }

    // これがTemplateMethodに相当するメソッド
    public function display()
    {
        $this->displayTitle();
        $this->displayArray();
    }

    // abstractとマークされたメソッドは、サブクラスにこれらのメソッドの定義を強制する
    // メソッドの外観を宣言するのみで実装を定義することはできない
    // 引数は定義できる
    abstract protected function displayTitle();

    abstract protected function displayArray();

}

// サブクラスその1
// 配列を改行区切りで返す
class BreakDisplay extends AbstractDisplay
{
    protected function displayTitle()
    {
        echo get_class()."クラスで配列を表示します"."<br>"."\n";
    }

    protected function displayArray()
    {
        foreach ($this->getData() as $value) {
            echo $value."<br>"."\n";
        }
    }
}

// サブクラスその2
// 配列をタブ区切りで返す
class TabDisplay extends AbstractDisplay
{
    protected function displayTitle()
    {
        echo get_class()."クラスで配列を表示します"."<br>"."\n";
    }

    protected function displayArray()
    {
        foreach ($this->getData() as $value) {
            echo $value."\t";
        }
    }
}

メソッドやプロパティのアクセス権(public、protected、private)、construct、abstractについても、別記事でまとめてみます!