LoginSignup
2
1

More than 5 years have passed since last update.

【PHPデザインパターン】14_Flyweight~同じものは一度しか作らない

Posted at

引用記事

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

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

Do You PHP はてな〜[doyouphp][phpdp]PHPによるデザインパターン入門 - Flyweight~同じものは一度しか作らない

概要

  • 一度インスタンス化したオブジェクトを使い回し、生成されるオブジェクトの数やリソースの消費を抑える。
  • 環境や状況によって変化しない情報は「intrinsic」(「本質的な」の意)、変化する情報は「extrinsic」(「非本質的な」の意)と呼ばれる。
  • Flyweightパターンでは、intrinsicな情報を持つオブジェクトが共有される。

構成要素

Flyweightクラス

  • 共有するオブジェクトの共通APIを定義する。

ConcreteFlyweightクラス

  • Flyweightクラスのサブクラス。
  • このクラスのインスタンスが共有されるので、intrinsicな情報のみ保持するようにする。

UnsharedConcreteFlyweightクラス

  • Flyweightクラスのサブクラス。
  • このクラスのインスタンスは共有されないので、extrinsicな情報を保持しても構わない。

FlyweightFactoryクラス

  • Flyweight型のインスタンスを生成・保持するクラス。

Clientクラス

  • Flyweight型のオブジェクトへの参照を保持するクラス。

ObjectPoolパターン

  • オブジェクトの数を制限して再利用する。
  • Flyweightパターンとの共通点が多い。
  • GoFパターンではない。

Think IT〜Object Poolパターン

実演

処理の流れ

  • Itemクラスのオブジェクトは、ItemFactoryクラスのメソッドからのみ呼び出せる。
  • オブジェクトが存在しない場合のみ、新規にオブジェクトを作成する。
  • UnsharedConcreteFlyweightクラスは、今回作成しない。

ファイル構造

MyFlyweight
  ├── Item.php
  ├── ItemFactory.php
  └── my_client.php

ソースコード

Flyweightクラス

兼ConcreteFlyweightクラス。

Item.php

Item.php
<?php
namespace DoYouPhp\PhpDesignPattern\Flyweight\MyFlyweight;

/**
 * FlyweightクラスとConcreteFlyweightクラスに相当する
 */
class Item
{
    private $id;
    private $name;
    private $price;

    // 各プロパティをセットする
    public function __construct($id, $name, $price)
    {
        $this->id = $id;
        $this->name = $name;
        $this->price = $price;
    }

    // 各要素を返すメソッド
    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }

    public function getPrice()
    {
        return $this->price;
    }
}

FlyweightFactoryクラス

ItemFactory.php

ItemFactory.php
<?php
namespace DoYouPhp\PhpDesignPattern\Flyweight\MyFlyweight;

use DoYouPhp\PhpDesignPattern\Flyweight\MyFlyweight\Item;

/**
 * FlyweightFactoryクラスに相当する
 * Singletonパターンにもなっている
 */
class ItemFactory
{
    private $pool;
    private static $instance = null;

    // コンストラクタ
    // 配列型のテスト用データからItemクラスのインスタンスを作成する
    private function __construct($data_array)
    {
        $this->buildPool($data_array);
    }

    // ItemFactoryクラスのインスタンスを返す
    // 同時にItemクラスのインスタンスが作成される
    // ItemFactoryクラスのインスタンスは、このメソッドからのみ返される
    public static function getInstance($data_array)
    {
        if (is_null(self::$instance)) {
            self::$instance = new ItemFactory($data_array);
        }

        return self::$instance;
    }

    // 引数のidに該当するItemクラスのインスタンスを返す
    public function getItem($id)
    {
        if (array_key_exists($id, $this->pool)) {
            return $this->pool[$id];
        } else {
            return;
        }
    }

    // 配列型のテスト用データを読み込み、Itemクラスのインスタンスを作成する
    // $poolはItemクラスのインスタンスを要素とする配列
    private function buildPool($data_array)
    {
        $this->pool = array();

        foreach ($data_array as $data) {
            $item_id   = $data['id'];
            $item_name = $data['name'];
            $price     = $data['price'];

            $this->pool[$item_id] = new Item($item_id, $item_name, $price);
        }
    }

    // インスタンスの複製を防ぐ
    final public function __clone()
    {
        throw new \RuntimeException(get_class($this).'クラスのインスタンスは複製できません');
    }
}

Clientクラス

my_client.php

my_client.php
<?php
namespace DoYouPhp\PhpDesignPattern\Flyweight\MyFlyweight;

require dirname(dirname(__DIR__)).'/vendor/autoload.php';

use DoYouPhp\PhpDesignPattern\Flyweight\MyFlyweight\ItemFactory;

// id,name,priceを表示する
function dumpData($data)
{
    foreach ($data as $object) {
        echo 'id:'.$object->getId().',name:'.$object->getName().',price:'.$object->getPrice().'<br>'."\n";
    }
}

// 配列型のテスト用データ
$data_array = array(
    array('id' => 1, 'name' => apple,  'price' => 100),
    array('id' => 2, 'name' => orange, 'price' => 80),
    array('id' => 3, 'name' => banana, 'price' => 130)
);

// ItemFactoryクラスのインスタンス作成と呼び出しを行う
$factory = ItemFactory::getInstance($data_array);

// idを引数にして、対応するItemクラスのインスタンスを取得する
// 配列itemsの要素としてセットする
$items = array();
$items[] = $factory->getItem(1);
$items[] = $factory->getItem(2);
$items[] = $factory->getItem(3);

// idが同じであれば、既存のオブジェクトと同じものである
if ($items[0] === $factory->getItem(1)) {
    echo '同一のオブジェクトです'.'<br>'."\n";
} else {
    echo '同一のオブジェクトではありません'.'<br>'."\n";
}

// 取得したデータのプロパティを出力する
dumpData($items);

// ItemFactoryクラスのオブジェクトは複製できないことを確認する
try {
    $factory_clone = clone $factory;
} catch (\RuntimeException $e) {
    echo $e->getMessage().'<br>'."\n";
}
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1