コンセプト
オブザーバー パターンは、オブジェクト間の 1 対多の依存関係を定義する動作パターンです。これにより、オブジェクトの状態が変化すると、それに依存するすべてのオブジェクトが通知され、自動的に更新されます。
オブジェクトの状態が変化すると、他のいくつかのオブジェクトの変化に影響を与えます。このとき、オブザーバー モードを使用できます。
オブザーバー パターンはインターフェイス分離原則に準拠し、オブジェクト間の疎結合を実現します。
Alias
Publish-Subscribe>パターン
Model-View
Slaveパターン
Abstract Subject (Subject): すべてのオブザーバーオブジェクトへの参照を保持します。でコレクションに含まれており、各トピックには任意の数のオブザーバーを含めることができます。抽象テーマは、オブザーバー オブジェクトを追加および削除するためのインターフェイスを提供します。
具体的なサブジェクト (ConcreteSubject): 特定のオブザーバー オブジェクトに関連するステータスを保存します。特定のサブジェクトの内部ステータスが変化すると、登録されているすべてのオブザーバーに通知が送信されます。
抽象オブザーバー (オブザーバー): すべての具体的なオブザーバーのインターフェイスを定義し、トピックによって通知されたときに自身を更新します。
具象オブザーバー: 抽象オブザーバーの役割が自身の状態をサブジェクト状態と調整するために必要な更新インターフェイスを実装します。
UML 図
コードサンプルコード
SplSubject インターフェイスと SqlOberver インターフェイスは PHP SPL で提供されています。ソース コードは次のとおりです:
/** * The <b>SplSubject</b> interface is used alongside * <b>SplObserver</b> to implement the Observer Design Pattern. * @link http://php.net/manual/en/class.splsubject.php */ interface SplSubject { /** * Attach an SplObserver * @link http://php.net/manual/en/splsubject.attach.php * @param SplObserver $observer <p> * The <b>SplObserver</b> to attach. * </p> * @return void * @since 5.1.0 */ public function attach (SplObserver $observer); /** * Detach an observer * @link http://php.net/manual/en/splsubject.detach.php * @param SplObserver $observer <p> * The <b>SplObserver</b> to detach. * </p> * @return void * @since 5.1.0 */ public function detach (SplObserver $observer); /** * Notify an observer * @link http://php.net/manual/en/splsubject.notify.php * @return void * @since 5.1.0 */ public function notify (); } /** * The <b>SplObserver</b> interface is used alongside * <b>SplSubject</b> to implement the Observer Design Pattern. * @link http://php.net/manual/en/class.splobserver.php */ interface SplObserver { /** * Receive update from subject * @link http://php.net/manual/en/splobserver.update.php * @param SplSubject $subject <p> * The <b>SplSubject</b> notifying the observer of an update. * </p> * @return void * @since 5.1.0 */ public function update (SplSubject $subject); }
ここで、これら 2 つの spl インターフェイスに基づいて独自のコードを作成します。 :
<?php header('Content-type:text/html;charset=utf-8'); /** * Class Subject 主题 */ class Subject implements SplSubject { private $_observers = []; /** * 实现添加观察者方法 * * @param SplObserver $observer */ public function attach(SplObserver $observer) { if (!in_array($observer, $this->_observers)) { $this->_observers[] = $observer; } } /** * 实现移除观察者方法 * * @param SplObserver $observer */ public function detach(SplObserver $observer) { if (false !== ($index = array_search($observer, $this->_observers))) { unset($this->_observers[$index]); } } /** * 实现提示信息方法 */ public function notify() { foreach ($this->_observers as $observer) { $observer->update($this); } } /** * 设置数量 * * @param $count */ public function setCount($count) { echo "数据量加" . $count . '<br>'; } /** * 设置积分 * * @param $integral */ public function setIntegral($integral) { echo "积分量加" . $integral . '<br>'; } } /** * Class Observer1 观察者一 */ class Observer1 implements SplObserver { public function update(SplSubject $subject) { $subject->setCount(10); } } /** * Class Observer2 观察者二 */ class Observer2 implements SplObserver { public function update(SplSubject $subject) { $subject->setIntegral(10); } } /** * Class Client 客户端 */ class Client { /** * 测试方法 */ public static function test() { // 初始化主题 $subject = new Subject(); // 初始化观察者一 $observer1 = new Observer1(); // 初始化观察者二 $observer2 = new Observer2(); // 添加观察者一 $subject->attach($observer1); // 添加观察者二 $subject->attach($observer2); // 消息提示 $subject->notify();//输出:数据量加1 积分量加10 // 移除观察者一 $subject->detach($observer1); // 消息提示 $subject->notify();//输出:数据量加1 积分量加10 积分量加10 } } // 执行测试 Client::test();
実行結果
データ量プラス10
ポイント量プラス10ポイント量プラス10
メリットとデメリット
メリット
観察者と被験者のカップリングが小さい。
ブロードキャスト通信をサポートします。
欠点
オブザーバーは他のオブザーバーの存在を認識しないため、ターゲットを変更する最終的なコストがわからない可能性があります。これにより、予期しない更新が発生する可能性があります。
適用可能なシナリオ
抽象モデルに 2 つの側面があり、一方が他方に依存する場合。
1 つのオブジェクトを変更するために同時に他のオブジェクトも変更する必要がある場合、変更する必要があるオブジェクトの数がわかりません。
オブジェクトが他のオブジェクトに通知する必要がある場合、他のオブジェクトが誰であるかを想定することはできません。言い換えれば、これらのオブジェクトを密結合にする必要はありません。