美文网首页
观察者模式及php委托

观察者模式及php委托

作者: 长刀无痕 | 来源:发表于2017-09-28 00:21 被阅读0次

    观察者模式的核心是将一个中心类(主体)和监控中心类的一些观察者做解耦合。面向对象设计核心思想就是面向抽象和接口编程,因此具体对象间,相互知道的越少越好,这样发生改变时才不至于互相影响。因此,对于观察者模式来说,目标和观察者不是紧密耦合的,目标所知道的仅仅是它有一系列的观察者,而观察者属于哪一个具体类,目标是没必要知道的。

    对于传统意义上的观察者模式来说,所有的观察者类都会实现一个抽象观察者接口,中心类会保存一组观察者对象的引用,当中心类的状态发生改变时,调用notify方法将已保存的观察者对象逐个更新,因为这是一个循环遍历,所以要求这些观察者对象必须有统一的接口。中心类同时也会有添加和移除观察者对象的方法。(调用代码见ClientController中的observe方法)

    但在实际使用过程中,主体和观察者可能早就已经存在了,他们之间根本就互相不知道,由客户端来决定通知谁。如果在C#中,可以利用委托来实现,在php里,可以用魔术方法来模拟C#里的委托。在主体类里增加一个$eventHandles数组,然后在客户端将观察者对象添加到这个数组里,这个时候相当于主体类也神奇的拥有了这些观察者类的方法。但这样做对于外部世界来说,提供的是一个动态的接口,没有办法进行反射,客户程序员无法一下子理清头绪。因此使用的时候最好有注释或文档提醒。(调用代码见ClientController中的observe1方法)

    <?php
    namespace Basic\Logic;
    
    class Subject
    {
        private $observers = [];
    
        public $eventHandles = [];
    
        public $subjectName;
    
        public function __construct($subjectName)
        {
            $this->subjectName = $subjectName . ' notify --';
        }
    
        public function attach(Observer $observer)
        {
            array_push($this->observers, $observer);
        }
    
        public function detach(Observer $observer)
        {
            foreach ($this->observers as $k => $v) {
                if ($observer == $v) {
                    unset($k);
                    break;
                }
            }
        }
    
        public function notify()
        {
            /** @var Observer $observer */
            foreach ($this->observers as $observer) {
                $observer->update($this);
            }
        }
    
        public function notify1()
        {
            foreach ($this->eventHandles as $eventHandle) {
                if (method_exists($eventHandle['obj'], $eventHandle['func'])) {
                    $eventHandle['obj']->$eventHandle['func']($this);
                }
            }
        }
    
        public function getState()
        {
            /** @var Observer $observer */
            foreach ($this->observers as $observer) {
                $observer->getState();
            }
        }
    
        public function __call($methodName, $args)
        {
            foreach ($this->eventHandles as $eventHandle) {
                if (method_exists($eventHandle, $methodName)) {
                    $eventHandle->$methodName($this);
                }
            }
        }
    }
    
    <?php
    namespace Basic\Logic;
    
    abstract class Observer
    {
        protected $state;
    
        abstract public function update(Subject $subject);
    
        public function getState()
        {
            echo $this->state . "<br>";
        }
    }
    
    <?php
    namespace Basic\Logic;
    
    class ObserverA extends Observer
    {
        protected $state = 'ObserverA';
    
        public function update(Subject $subject)
        {
            $this->state = $subject->subjectName . 'notify observerA';
            echo $this->state . "<br>";
        }
    
        public function closeState(Subject $subject)
        {
            $this->state = $subject->subjectName . 'close observerA';
            echo $this->state . "<br>";
        }
    
    }
    
    <?php
    namespace Basic\Logic;
    
    class ObserverB extends Observer
    {
    
        protected $state = 'ObserverB';
    
        public function update(Subject $subject)
        {
            $this->state = $subject->subjectName . 'notify observerB';
            echo $this->state . "<br>";
        }
    
        public function openState(Subject $subject)
        {
            $this->state = $subject->subjectName . 'open observerB';
            echo $this->state . "<br>";
        }
    }
    

    observe2方法是observe1方法的另一种更简洁的写法。这三种写法各有利弊,具体的实现需要根据真实的环境来做出选择。

    <?php
    namespace Basic\Controller;
    
    use Basic\Logic\ObserverA;
    use Basic\Logic\ObserverB;
    use Basic\Logic\Subject;
    
    class ClientController
    {
        public function observe()
        {
            $subject = new Subject('subjectB');
            $subject->attach(new ObserverA());
            $subject->attach(new ObserverB());
            $subject->notify();
        }
    
        public function observe1()
        {
            $subject = new Subject('subjectB');
            $subject->eventHandles[] = new ObserverA();
            $subject->eventHandles[] = new ObserverB();
            $subject->closeState();
            $subject->openState();
        }
    
        public function observe2()
        {
            $subject = new Subject('subjectB');
            $subject->eventHandles[] = [
                'obj'  => new ObserverA(),
                'func' => 'closeState'
            ];
            $subject->eventHandles[] = [
                'obj'  => new ObserverB(),
                'func' => 'openState'
            ];
            $subject->notify1();
        }
    }
    

    版权声明:本文为原创文章,转载请注明出处,谢谢~~

    相关文章

      网友评论

          本文标题:观察者模式及php委托

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