traitでデザインパターン再考
こんにちは。php5.4adventカレンダーの10日目「PHP5.4でのhtmlspecialcharsの仕様変更とセキュリティ」を引き継いで11日目担当のPaulです。
PHP5.4で出てくるtraitこれのメリットとして、
- mix-inができる。
- あとでメソッド名再定義できるから、名前当たってもOK
みたいな事がRFCに書いてありましたが、
僕がRFCを眺めて感じたメリットは 親クラス作らなくても、実装の再利用が出来る!って事でした。
いや、ちゃんと親クラス作って、それを実装を追加したいクラスでextendして…
てやればタイプヒントの恩恵に預かれるのは分かってますが、、、
それをする余裕が無いことってありますヤン。
もちろんデリゲートも知ってますけど、あれはあれで追加のコード量が半端ないですヤン。
traitやったら、1個trait作っておけば、あとから実装追加したいクラスにuseなんちゃらって1行書くだけで済みますヤン。
それにもともと、タイプヒントでやってるクラスと、そうでないクラス両方に共通の実装ってなると何かと面倒でっしゃろ。
で、、、あとから実装を追加したくなるのってどのデザインパターンかなと思って このサイトを眺めてたら
- Decorator
- Visitor
- Observer
ぐらい?
この中で一番簡単そうなObserverパターンをtraitで書いて見ました。
まずはSubject trait
trait Subject {
/**
* Observer追加
*
* @param Observer $observer
*/
public function attach(Observer $observer)
{
array_push($this->observers, $observer);
}
/**
* SplSubjectと同じ名前で通知を定義
*/
public function notify($funcName)
{
foreach ($this->observers as $key => $item) {
$item->update([$this, $funcName]);
}
}
}
次はObserver
class Observer
{
public function update(Callable $f)
{
$f();
}
}
最後にSubjectの実装
class AKB
{
use Subject; //この2行を付け足すだけで
private $observers = array(); //ObserverのSubjectになる。
private $members = array();
private $latest;
/**
* メンバーが追加される度に通知
*/
public function addMember($member)
{
array_push($this->members, $member);
$this->notify('getLatest');
}
/**
* Observerで呼び出される。
*/
public function getLatest()
{
echo $this->members[count($this->members) -1] . "が加わりました!" . PHP_EOL;
}
}
実行すると
$o = new Observer();
$akb = new AKB();
$akb->attach($o);
$akb->addMember("前田敦子");
$akb->addMember("大島優子");
$akb->addMember("柏木由紀");
"前田敦子が加わりました!" "大島優子が加わりました!" "柏木由紀が加わりました!"
僕的には作ったあと、「これ本当に便利になったかな?」って思ってしまいましたが、
既存のクラスに少し手を加えるだけ良いし、
例えばAKBクラスが親クラスを持っていたら今までは親クラスに変更を入れるかinterfaceをインプリメントするコードを書かなければいけなかったので、楽になったと思います!
次回12日目は@co3kさんです!お楽しみに
追記:12月12日 class AKBのところにバグが有ったので修正しました。