laiyuquan

博客

观察者模式(Observer)

 

 

模式概念

观察者模式有时也被称为发布/订阅模式,该模式用于为对象实现发布/订阅功能;一旦主体对象状态发生改变,与之关联的观察者对象也会收到通知,并进行相关的操作

特点:

  • 在主体中可以添加任意个观察者;
  • 在主体中可以删除任意某个歌观察者;
  • 当主体发生改变可以通知观察者,以便观察者进行相关的处理;
  • 主体和观察者 完全实现解耦

应用场景

  1. 消息队列系统
  2. 事件监听机制
  3. 支持广播通信

UML类图

《观察者模式(Observer)》

代码实现

User.php(被观察者

<?php

namespace DesignPatterns\Behavioral\Observer;

/**
 * User implements the observed object (called Subject), it maintains a list of observers and sends notifications to
 * them in case changes are made on the User object
 */
class User implements \SplSubject
{
    /**
     * @var string
     */
    private $email;

    /**
     * @var \SplObjectStorage
     */
    private $observers;

    public function __construct()
    {
        $this->observers = new \SplObjectStorage();
    }

    public function attach(\SplObserver $observer)
    {
        $this->observers->attach($observer);
    }

    public function detach(\SplObserver $observer)
    {
        $this->observers->detach($observer);
    }

    public function changeEmail(string $email)
    {
        $this->email = $email;
        $this->notify();
    }

    public function notify()
    {
        /** @var \SplObserver $observer */
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }
}

UserObserver.php(观察者)

<?php

namespace DesignPatterns\Behavioral\Observer;

class UserObserver implements \SplObserver
{
    /**
     * @var User[]
     */
    private $changedUsers = [];

    /**
     * It is called by the Subject, usually by SplSubject::notify()
     *
     * @param \SplSubject $subject
     */
    public function update(\SplSubject $subject)
    {
        $this->changedUsers[] = clone $subject;
    }

    /**
     * @return User[]
     */
    public function getChangedUsers(): array
    {
        return $this->changedUsers;
    }
}

ObserverTest.php

<?php

namespace DesignPatterns\Behavioral\Observer\Tests;

use DesignPatterns\Behavioral\Observer\User;
use DesignPatterns\Behavioral\Observer\UserObserver;
use PHPUnit\Framework\TestCase;

class ObserverTest extends TestCase
{
    public function testChangeInUserLeadsToUserObserverBeingNotified()
    {
        $observer = new UserObserver();


        $user = new User();
        $user->attach($observer);

        $user->changeEmail('foo@bar.com');
        $this->assertCount(1, $observer->getChangedUsers());

    }
}

心得总结

  • 某一个主体发生改变,通过被观察者进行处理
  • PHP SPL标准中已经提供SplSubject 和 SplObserver,主体继承splSubject接口,观察者继承SplObserver接口,即可以直接使用观察者模式
  • 被观察者完全不需要关心观察者,对象之间不必相互理解,同样能够相互通信
点赞

发表评论