美文网首页
观察者模式及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