观察者模式的核心是将一个中心类(主体)和监控中心类的一些观察者做解耦合。面向对象设计核心思想就是面向抽象和接口编程,因此具体对象间,相互知道的越少越好,这样发生改变时才不至于互相影响。因此,对于观察者模式来说,目标和观察者不是紧密耦合的,目标所知道的仅仅是它有一系列的观察者,而观察者属于哪一个具体类,目标是没必要知道的。
对于传统意义上的观察者模式来说,所有的观察者类都会实现一个抽象观察者接口,中心类会保存一组观察者对象的引用,当中心类的状态发生改变时,调用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();
}
}
版权声明:本文为原创文章,转载请注明出处,谢谢~~