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

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

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

久しぶりの二日酔いで寝込んでいました。
仕事がたまって大変ですが、このシリーズももう少しで終わりなので頑張ってアウトプットしてみます。

Observer、スナップショットを取る

振る舞い + オブジェクト
今回はObserverパターン。
javascriptだと(個人的に)よく使うパターンです。

商品追加と通知

商品が追加、削除されるタイミングにフックしてみます。

/*
商品の管理とObserverへの通知を行う
*/
class Cart
{
	//商品
	private $items;
	//リスナー
	private $listeners;
	
	//コンストラクタ
	public function __construct()
	{
		$this->items = array();
		$this->listeners = array();
	}
	
	//商品の追加
	public function addItem($item_cd)
	{
		$this->items[$item_cd] = (isset($this->items[$item_cd])) ? ++$this->items[$item_cd] : 1;
		$this->notify();
	}
	
	//商品の削除
	public function removeItem($item_cd)
	{
		$this->items[$item_cd] = (isset($this->items[$item_cd])) ? --$this->items[$item_cd] : 0;
		if($this->items[$item_cd]<=0) unset($this->items[$item_cd]);
		$this->notify();
	}
	
	//商品の取得
	public function getItems()
	{
		return $this->items;
	}
	
	//商品の存在チェック
	public function hasItem($item_cd)
	{
		return array_key_exists($item_cd,$this->items);
	}
	
	//Observerを登録
	public function addListener(CartListner $listener)
	{
		$this->listener[get_class($listener)] = $listener;
	}
	
	//Observerを削除
	public function removeListener(CartListner $listener)
	{
		unset($this->listener[get_class($listener)]);	}
	
	//Observerへ通知
	public function notify()
	{
		foreach ($this->listener as $listener) {
			$listener->update($this);
		}	
	}
}

インターフェイス

オブザーバーに共通のIFを定義します。

/*
リスナーインターフェイス
*/
interface CartListner
{
	public function update(Cart $cart);
}

リスナー1 プレゼントの判定

/*
オブザーバークラス 商品の追加
*/
class PresentListener implements CartListner
{
	private static $PRESENT_TARGET_ITEM = '30:クッキーセット';
	private static $PRESENT_ITEM = '90:プレゼント';
	
	//更新処理
	public function update(Cart $cart)
	{
		if($cart->hasItem(self::$PRESENT_TARGET_ITEM) && !$cart->hasItem(self::$PRESENT_ITEM) )
		{
			$cart->addItem(self::$PRESENT_ITEM);
		}
		else if(!$cart->hasItem(self::$PRESENT_TARGET_ITEM) && $cart->hasItem(self::$PRESENT_ITEM) )
		{
			$cart->removeItem(self::$PRESENT_ITEM);		}		
	}
}

リスナー2 登録状況のダンプ

/*
オブザーバークラス 商品のダンプ
*/
class LoggingListener implements CartListner
{
	//更新処理
	public function update(Cart $cart)
	{
		var_dump($cart->getItems());
	}	
}

追加してみる

//ログリスナーの登録
$cart = new Cart();
$cart->addListener(new LoggingListener);
//商品の追加
$cart->addItem("10:Tシャツ");

//プレゼント追加リスナーの登録
$cart->addListener(new PresentListener);
//プレゼント追加
$cart->addItem("30:クッキーセット");
$php listener.php
array(1) {
  ["10:Tシャツ"]=>
  int(1)
}

array(2) {
  ["10:Tシャツ"]=>
  int(1)
  ["30:クッキーセット"]=>
  int(1)
}

array(3) {
  ["10:Tシャツ"]=>
  int(1)
  ["30:クッキーセット"]=>
  int(1)
  ["90:プレゼント"]=>
  int(1)
}

特定のフックポイントに任意の処理を差し込むことが可能になりました。
ポイントを複数作って実装すると拡張が楽になるパターンなので活用したいですね!

Add a Comment

メールアドレスが公開されることはありません。