cheka.jp 超不定期で更新する写真達。お口直しにどうぞ。

[写経] PHPで学ぶデザインパターン18

— 注意 —
PHPによるデザインパターンの写経ですが、まんま書くと問題があるのでアウトプットとして備忘録メモです

Prototype、コピーして作る

生成 + オブジェクト
オブジェクトの雛形を準備し、インスタンスを生成するときに準備した雛形を利用します。
浅いコピーと深いコピーを意識する必要はありますが、Factoryパターンと使い分けて活用出来るパターンです。

テンプレートの抽象クラス

/*
ProtoTypeクラス
*/
abstract class ItemPrototype
{
	private $item_code;
	private $item_name;
	private $price;
	private $detail;
	
	//コンストラクタ
	public function __construct($item_code,$item_name,$price)
	{
		$this->item_code = $item_code;
		$this->item_name = $item_name;
		$this->price = $price;
	}
	
	//アイテムコードの取得
	public function getItemCode()
	{
		return $this->item_code;
	}

	//アイテム名の取得
	public function getItemName()
	{
		return $this->item_name;
	}
	
	//価格の取得
	public function getPrice()
	{
		return $this->price;
	}	
	
	//詳細の設定
	public function setDetail(stdClass $detail)
	{
		$this->detail = $detail;
	}

	//詳細の取得
	public function getDetail()
	{
		return $this->detail;
	}

	//インスタンスの複製
	public function newInstance()
	{
		return clone $this;
	}	
	
	protected abstract function __clone();
	
	//デバック用
	public function dumpData()
	{
		print $this->getItemCode()."\n";
		print $this->getItemName()."\n";
		print number_format($this->getPrice())."\n";		print $this->detail->comment;
	}
}

深いコピーのテンプレート

/*
内部で保持しているオブジェクトまでコピーするクラス
*/
class DeepCopyItem extends ItemPrototype
{
	protected function __clone()
	{
		$this->setDetail(clone $this->getDetail());
	}
}

浅いコピーのテンプレート

/*
内部で保持しているオブジェクトはコピーしないクラス
*/
class ShallowCopyItem extends ItemPrototype
{
	protected function __clone()
	{
	}	
}

雛形を管理するクラス

/*
商品を管理するクラス
*/
class ItemManager
{
	private $items;
	
	//コンストラクタ
	public function __construct()
	{
		$this->items = array();
	}
	
	//アイテムの登録
	public function registItem(ItemPrototype $item)
	{
		$this->items[$item->getItemCode()] = $item;
	}
	
	//プロトタイプからインスタンスを生成する
	public function create($item_code)
	{
		if( !array_key_exists($item_code,$this->items) )
		{
			throw new Exception("iten_code[".$item_code."] not exists!");
		}
		return $this->items[$item_code]->newInstance();
	}
}

使ってみる

//アイテムマネージャーの生成
$itemManager = new ItemManager();

//深いコピーに対応した商品を生成
$deep = new DeepCopyItem("DEEP01","アイテムDeep01",1000);
$deepDetail = new stdClass();
$deepDetail->comment = 'アイテムDeep01のコメントです';
$deep->setDetail($deepDetail);

//浅いコピーの商品を生成
$shallow = new ShallowCopyItem("SHALLOW01","アイテムShallow01",2000);
$shallowDetail = new stdClass();
$shallowDetail->comment = 'アイテムShallow01のコメントです';
$shallow->setDetail($shallowDetail);

//マネージャーに登録
$itemManager->registItem($deep);
$itemManager->registItem($shallow);

//deepをコピー
$copy1 = $itemManager->create("DEEP01");
$copy2 = $itemManager->create("DEEP01");
$copy2->getDetail()->comment = "コメント書き換え";

print "1)オリジナル\n";
$copy1->dumpData();
print "\n\n";

print "2)コピー\n";
$copy2->dumpData();
print "\n\n";

//shallowをコピー
$copy1 = $itemManager->create("SHALLOW01");
$copy2 = $itemManager->create("SHALLOW01");
$copy2->getDetail()->comment = "コメント書き換え";

print "3)オリジナル\n";
$copy1->dumpData();
print "\n\n";

print "4)コピー\n";
$copy2->dumpData();
print "\n";

[bush]
$php prototype.php
[/bush]

1)オリジナル
DEEP01
アイテムDeep01
1,000
アイテムDeep01のコメントです

2)コピー
DEEP01
アイテムDeep01
1,000
コメント書き換え

3)オリジナル
SHALLOW01
アイテムShallow01
2,000
コメント書き換え

4)コピー
SHALLOW01
アイテムShallow01
2,000
コメント書き換え

コピーする深さと雛形を管理するクラスの関係を理解するのがポイントになりそうです。