PHP7でデザインパターン入門6/23 Prototypeパターン

Prototype パターンとは

生成されるオブジェクトの種別がプロトタイプ(典型)的なインスタンスであるときに使用され、このプロトタイプを複製して新しいオブジェクトを生成する。 このパターンは Abstract Factory パターンでなされるように、クライアント・アプリケーションにおいてオブジェクトの生成者をサブクラスにすることを回避する。 標準的な方法(例えば'new')で新しいオブジェクトを作ることによる固有のコストが所与のアプリケーションにとって高すぎる時にそれを回避する。

Prototype パターン - Wikipedia

具体的には以下のような場合にインスタンスを複製して新しいインスタンスを生成するパターンのようだ。

example

以下サンプルプログラム。 文字列を枠線を囲って表示したり、下線を引いて表示したりするもの。

Framework/Manager クラス

<?php
class Manager
{
    private $showcase = [];

    public function register(string $name, Product $proto)
    {
        $this->showcase[$name] = $proto;
    }

    public function create(string $protoname): Product
    {
        $p = $this->showcase[$protoname];
        return $p->createClone();
    }
}

Framework/Product インターフェース

<?php
interface Product
{
    public function use(string $s);
    public function createClone(): Product;
}

UnderlinePen クラス

<?php
class UnderlinePen implements Product
{
    private $ulchar;

    public function __construct(string $ulchar)
    {
        $this->ulchar = $ulchar;
    }

    public function use(string $s)
    {
        $length = strlen(mb_convert_encoding($s, 'SJIS', 'UTF-8'));
        echo "\"{$s}\"" . PHP_EOL . " ";
        for ($i = 0; $i < $length; $i++) {
            echo $this->ulchar;
        }
        echo PHP_EOL;
    }

    public function createClone(): Product
    {
        $p = null;
        try {
            $p = clone $this;
        } catch (Exception $e) {
            $e->getTrace();
        }
        return $p;
    }
}

MessageBox クラス

<?php
class MessageBox implements Product
{
    private $decochar;

    public function __construct(string $decochar)
    {
        $this->decochar = $decochar;
    }

    public function use(string $s)
    {
        $length = strlen(mb_convert_encoding($s, 'SJIS', 'UTF-8'));

        for ($i = 0; $i < $length + 4; $i++) {
            echo($this->decochar);
        }
        echo PHP_EOL . "{$this->decochar} {$s} {$this->decochar}" . PHP_EOL;
        for ($i = 0; $i < $length + 4; $i++) {
            echo $this->decochar;
        }
        echo PHP_EOL;
    }

    public function createClone(): Product
    {
        $p = null;
        try {
            $p = clone $this;
        } catch (Exception $e) {
            $e->getTrace();
        }
        return $p;
    }
}

main

<?php
$manager = new Manager();
$upen = new UnderlinePen('~');
$mbox = new MessageBox('*');
$sbox = new MessageBox('/');
$manager->register("strong message", $upen);
$manager->register("warning box", $mbox);
$manager->register("slash box", $sbox);

$p1 = $manager->create("strong message");
$p1->use("Hello, world.");
$p2 = $manager->create("warning box");
$p2->use("Hello, world.");
$p3 = $manager->create("slash box");
$p3->use("Hello, world.");

実行結果

"Hello, world."
 ~~~~~~~~~~~~~
*****************
* Hello, world. *
*****************
/////////////////
/ Hello, world. /
/////////////////

ソースコード

github.com

役割

  • Product: framework. インターフェース。useとcreateCloneのみ宣言されている。
  • Manager: framework. createCloneを使ってインスタンスを複製するクラス
  • MessageBox: 文字列を枠線で囲って表示するクラス。Productインターフェースを実装している。
  • UnderlinePen: 文字列に下線を引いて表示するクラス。Productをインターフェースを実装している。

まとめ

Prototypeは、インスタンスから新しいインスタンスを複製するパターンである。

関連パターン

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

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