オブザーバー パターンは、パブリッシュ/サブスクライブ パターンと呼ばれることもあります。このパターンは、オブジェクトのパブリッシュ/サブスクライブ機能を実装するために使用されます。サブジェクト オブジェクトの状態が変化すると、オブザーバー オブジェクトが関連付けられます。通知を受信し、それに応じて動作します。
システムを相互に連携するクラスに分割すると、関連するオブジェクト間の一貫性を維持する必要があるという悪い副作用が生じます。一貫性を維持するためにさまざまな種類のアプリケーションを密結合することは望ましくありません。これにより、メンテナンス、拡張、再利用に不便が生じます。オブザーバーは、この種の結合関係を解決します。
メッセージ キュー システムとイベントはすべてオブザーバー パターンを使用します。
PHP は、オブザーバー パターンに対して SplSubject と SplObserver という 2 つのインターフェイスを定義します。 SplSubject はサブジェクト オブジェクトの抽象化として見ることができ、SplObserver はオブザーバー オブジェクトの抽象化として見ることができます。オブザーバー パターンを実装するには、サブジェクト オブジェクトに SplSubject を実装させ、オブザーバー オブジェクトに SplObserver を実装させるだけで済みます。対応するメソッド。
User.php
<?phpnamespace DesignPatterns\Behavioral\Observer;/** * 观察者模式 : 被观察对象 (主体对象) * * 主体对象维护观察者列表并发送通知 * */class User implements \SplSubject{ /** * user data * * @var array */ protected $data = array(); /** * observers * * @var \SplObjectStorage */ protected $observers; public function __construct() { $this->observers = new \SplObjectStorage(); } /** * 附加观察者 * * @param \SplObserver $observer * * @return void */ public function attach(\SplObserver $observer) { $this->observers->attach($observer); } /** * 取消观察者 * * @param \SplObserver $observer * * @return void */ public function detach(\SplObserver $observer) { $this->observers->detach($observer); } /** * 通知观察者方法 * * @return void */ public function notify() { /** @var \SplObserver $observer */ foreach ($this->observers as $observer) { $observer->update($this); } } /** * * @param string $name * @param mixed $value * * @return void */ public function __set($name, $value) { $this->data[$name] = $value; // 通知观察者用户被改变 $this->notify(); }}
UserObserver.php
<?phpnamespace DesignPatterns\Behavioral\Observer;/** * UserObserver 类(观察者对象) */class UserObserver implements \SplObserver{ /** * 观察者要实现的唯一方法 * 也是被 Subject 调用的方法 * * @param \SplSubject $subject */ public function update(\SplSubject $subject) { echo get_class($subject) . ' has been updated'; }}
Tests/ObserverTest.php
<?phpnamespace DesignPatterns\Behavioral\Observer\Tests;use DesignPatterns\Behavioral\Observer\UserObserver;use DesignPatterns\Behavioral\Observer\User;/** * ObserverTest 测试观察者模式 */class ObserverTest extends \PHPUnit_Framework_TestCase{ protected $observer; protected function setUp() { $this->observer = new UserObserver(); } /** * 测试通知 */ public function testNotify() { $this->expectOutputString('DesignPatterns\Behavioral\Observer\User has been updated'); $subject = new User(); $subject->attach($this->observer); $subject->property = 123; } /** * 测试订阅 */ public function testAttachDetach() { $subject = new User(); $reflection = new \ReflectionProperty($subject, 'observers'); $reflection->setAccessible(true); /** @var \SplObjectStorage $observers */ $observers = $reflection->getValue($subject); $this->assertInstanceOf('SplObjectStorage', $observers); $this->assertFalse($observers->contains($this->observer)); $subject->attach($this->observer); $this->assertTrue($observers->contains($this->observer)); $subject->detach($this->observer); $this->assertFalse($observers->contains($this->observer)); } /** * 测试 update() 调用 */ public function testUpdateCalling() { $subject = new User(); $observer = $this->getMock('SplObserver'); $subject->attach($observer); $observer->expects($this->once()) ->method('update') ->with($subject); $subject->notify(); }}
オブザーバーパターン主体と具体的な観察者を切り離し、双方が具体的なものではなく抽象的なものに依存するようにします。そのため、それぞれの側での変更がもう一方の側の変更に影響を与えません。