美文网首页
PHP设计模式(5)-观察者模式

PHP设计模式(5)-观察者模式

作者: EwanRenton | 来源:发表于2018-07-26 16:35 被阅读0次

    layout: post
    title: "PHP设计模式(5)-观察者模式"
    date: 2016-06-06 23:06:22 +0800
    comments: true
    categories:


    1、模式定义

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

    将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。

    消息队列系统、事件都使用了观察者模式。

    PHP 为观察者模式定义了两个接口:SplSubjectSplObserverSplSubject 可以看做主体对象的抽象,SplObserver 可以看做观察者对象的抽象,要实现观察者模式,只需让主体对象实现 SplSubject ,观察者对象实现 SplObserver,并实现相应方法即可。

    2、UML类图

    image

    3、示例代码

        <?php
        
        namespace 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();//PHP SPL标准库之数据结构对象容器
            }
        
            /**
             * 附加观察者
             *
             * @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();
            }
        }
    
        <?php
        
        namespace DesignPatterns\Behavioral\Observer;
        
        /**
         * UserObserver 类(观察者对象)
         */
        class UserObserver implements \SplObserver
        {
            /**
             * 观察者要实现的唯一方法
             * 也是被 Subject 调用的方法
             *
             * @param \SplSubject $subject
             */
            public function update(\SplSubject $subject)
            {
                echo get_class($subject) . ' has been updated';
            }
        }
    
        <?php
        
        namespace 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;//访问不存在的属性自动调用__set方法
            }
        
            /**
             * 测试订阅
             */
            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();
            }
        }
    

    4、总结

    观察者模式解除了主体和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。

    相关文章

      网友评论

          本文标题:PHP设计模式(5)-观察者模式

          本文链接:https://www.haomeiwen.com/subject/byibmftx.html