一言で言うと?
共通の処理は抽象クラスで実装し、サブクラスで冗長になるような処理は実装せずに、抽象メソッドとして定義しておき、サブクラスで具体的な処理を実装する。
どんなシチュエーションで使うの?
- 共通の処理を持つオブジェクトをいくつも実装したい
- しかしそれぞれのオブジェクトでは共通の処理とは別に固有の処理を持たせたい
そもそもデザインパターンとは?
すでに編み出された設計のノウハウを蓄積し、再利用しやすいように取りまとめたもの。
実装
実装の概要
- AbstractChefという抽象クラスが存在する
- AbstractChefクラスには以下のメソッドが定義されている
- サブクラスで共通して使用する処理内容が実装されたworkメソッド(シェフとしての仕事をする)
- サブクラス毎に具体的な処理内容が変動するgetIngredientsメソッドとcookメソッド(食材の仕入れと調理)
- サブクラスで共通して使用する処理内容が実装されたworkメソッド(シェフとしての仕事をする)
- SushiChefクラスとPizzaChefクラスがAbstractChefを継承する(寿司職人とピザ職人)
- それぞれ寿司職人とピザ職人では食材の仕入れ方や調理方法、工程などが変わるため、具体的な処理を個々のクラスで実装する
サンプルコード
抽象クラス
AbstractChef.php
<?php
namespace App\Chef;
abstract class AbstractChef
{
private $name;
public function __construct(string $name)
{
$this->name = $name;
}
/**
* 共通の処理内容
*
* Undocumented function
*
* @return void
*/
public function work(): void
{
$this->getIngredients();
$this->cook();
}
/**
* 食材の調達
*
* Undocumented function
*
* @return void
*/
protected abstract function getIngredients(): void;
/**
* 調理
*
* Undocumented function
*
* @return void
*/
protected abstract function cook(): void;
/**
* 名前を取得
*
* Undocumented function
*
* @return string
*/
public function getName(): string
{
return $this->name;
}
}
サブクラス
SushiChef.php
<?php
namespace App\Chef;
use App\Chef\AbstractChef;
require 'vendor/autoload.php';
class SushiChef extends AbstractChef
{
protected function getIngredients(): void
{
$chef = $this->getName();
echo $chef . 'は市場でマグロを買います。' . "\n";
echo $chef . 'は知り合いの農家から米をもらいます。' . "\n";
echo $chef . 'は近所のスーパーでお酢を買います。' . "\n";
}
protected function cook(): void
{
$chef = $this->getName();
echo $chef . 'は米を炊き、お酢を混ぜます。' . "\n";
echo $chef . 'はマグロをさばきます。' . "\n";
echo $chef . 'はネタとシャリを握ります。' . "\n";
echo '寿司が出来ました。' . "\n";
}
}
PizzaChef.php
<?php
namespace App\Chef;
use App\Chef\AbstractChef;
require 'vendor/autoload.php';
class PizzaChef extends AbstractChef
{
protected function getIngredients(): void
{
$chef = $this->getName();
echo $chef . 'は実家の畑から小麦を収穫します。' . "\n";
echo $chef . 'は知り合いの酪農家からチーズをもらいます。' . "\n";
echo $chef . 'は近所のスーパーでトマトソースを買います。' . "\n";
}
protected function cook(): void
{
$chef = $this->getName();
echo $chef . 'は小麦粉をこねて生地を作ります。' . "\n";
echo $chef . 'は生地にトマトソースをぬります。' . "\n";
echo $chef . 'は生地にチーズをのせます。' . "\n";
echo $chef . 'は生地を焼きます。' . "\n";
echo 'ピザが出来ました。' . "\n";
}
}
実行クラス
TemplateMethod.php
<?php
namespace App\Chef;
require 'vendor/autoload.php';
use App\Chef\PizzaChef;
use App\Chef\SushiChef;
doTemplateMethod1('Taro');
doTemplateMethod2('John');
/**
* 実行メソッド1
*
* Undocumented function
*
* @param string $name
* @return void
*/
function doTemplateMethod1(string $name): void
{
$japanese_chef = new SushiChef($name);
$japanese_chef->work();
}
/**
* 実行メソッド2
*
* Undocumented function
*
* @param string $name
* @return void
*/
function doTemplateMethod2(string $name): void
{
$japanese_chef = new PizzaChef($name);
$japanese_chef->work();
}
実行結果
Taroは市場でマグロを買います。
Taroは知り合いの農家から米をもらいます。
Taroは近所のスーパーでお酢を買います。
Taroは米を炊き、お酢を混ぜます。
Taroはマグロをさばきます。
Taroはネタとシャリを握ります。
寿司が出来ました。
Johnは実家の畑から小麦を収穫します。
Johnは知り合いの酪農家からチーズをもらいます。
Johnは近所のスーパーでトマトソースを買います。
Johnは小麦粉をこねて生地を作ります。
Johnは生地にトマトソースをぬります。
Johnは生地にチーズをのせます。
Johnは生地を焼きます。
ピザが出来ました。
参考
「PHPによるデザインパターン入門 - TemplateMethod〜処理を穴埋めする」
http://shimooka.hateblo.jp/entry/20141212/1418363698