本記事に掲載したサンプルコードは、https://github.com/ryo-utsunomiya/design_patternでも公開中です。
Prototypeとは
クラスからインスタンスを生成するのではなく、インスタンスから別のインスタンスを作り出すことを、Prototypeパターンと呼びます。
Prototypeパターンの例として、Productという文字列を表示するインタフェースと、Productインスタンスの生成及び管理を行うManagerというクラスが存在するとします。
<?php
namespace myframework;
interface Product {
/**
* @param string $s
*/
public function display($s);
}
<?php
namespace myframework;
class Manager
{
/**
* @var Product[]
*/
private $showCase;
/**
* @param string $name
* @param Product $proto
*/
public function register($name, Product $proto)
{
$this->showCase[$name] = $proto;
}
/**
* @param string $protoName
* @return Product
*/
public function create($protoName)
{
if (isset($this->showCase[$protoName])) {
return clone $this->showCase[$protoName];
} else {
throw new InvalidArgumentException();
}
}
}
次に、Productインタフェースを実装したUnderlinePenクラスを作成します。このクラスは、与えられた文字列を使用して下線を引きます。
<?php
namespace my;
use myframeworkProduct;
class UnderlinePen implements Product
{
/**
* @var string
*/
private $ulChar;
/**
* @param $ulChar
*/
public function __construct($ulChar)
{
$ulChar = (string)$ulChar;
$this->ulChar = $ulChar[0];
}
/**
* @param string $s
*/
public function display($s)
{
$length = strlen($s);
echo '"' . $s . '"' . PHP_EOL;
echo ' ';
for ($i = 0; $i < $length; $i++) {
echo $this->ulChar;
}
echo PHP_EOL;
}
}
以下が、これらのクラスの使用例です。
< ?php
namespace my;
use myframeworkManager;
require_once __DIR__ . '/../autoload.php';
$manager = new Manager();
$manager->register('strong message', new UnderlinePen('~'));
$manager->create('strong message')->display('Hello, World');
これを実行すると、以下のように表示されます。
"Hello, World"
~~~~~~~~~~~~
このコードだとありがたみが分かりづらいですが、UnderlinePenのインスタンスを生成するのが難しい場合などには、一度インスタンスを生成しておいて、後で再利用できるようになっていると便利そうですね。