PHP观察者模式
什么是观察者模式?
- 从面向过程的角度来看,首先是观察者向主题注册,注册完之后,主题再通知观察者做出相应的操作,整个事情就完了
- 从面向对象的角度来看,主题提供注册和通知的接口,观察者提供自身操作的接口。(这些观察者拥有一个同一个接口。)观察者利用主题的接口向主题注册,而主题利用观察者接口通知观察者。耦合度相当之低
流程图如下:
为什么要用观察者模式?
- 观察者模式更多体现了两个独立的类利用接口完成一件本应该很复杂的事情。不利用主题类的话,我们还需要不断循环创建实例,执行操作。而现在只需要创建实例就好,执行操作的事儿只需要调用一次通知的方法就好啦
应用场景
- 当一个对象的改变需要同时改变其他对象的时候,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。
代码一
$a = new A();
// 注入观察者
$a->addObserver(new B());
$a->addObserver(new C());
// 可以看到观察到的信息
$a->addListener('D');
// 移除观察者
$a->removeObserver('B');
// 打印的信息:
// object(A)#1 (1) { ["observers":protected]=> array(2) { [0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } [1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } }
// string(1) "D"
// object(A)#1 (1) { ["observers":protected]=> array(2) { [0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } [1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } }
// string(1) "D"
/**
* @purpose: 观察者接口, 定义观察者具体需要执行的方法,当然方法名和方法个数可以自定义
* Interface Observer
*/
interface Observer
{
/**
* @purpose: 广播通知后,所有已注册的观察者都需要执行该方法。
* @return mixed
*/
public function eat();
}
/**
* @purpse: 定义猫猫类,继承观察者接口,实现具体细节
* Class Cat
*/
class Cat implements Observer
{
public function eat()
{
echo 'Cat eat fish';
}
}
/**
* @purpse: 定义狗狗类,继承观察者接口,实现具体细节
* Class Dog
*/
class Dog implements Observer
{
public function eat()
{
echo 'Dog eat bones';
}
}
/**
* @purpose: 主题接口, 定义添加观察者和广播通知的方法
* Interface Notify
*/
interface Subject
{
/**
* @purpose: 添加观察者
* @param string $key 给所添加的观察者的一个唯一 key,方便从注册树中移除观察者
* @param Observer $observer 观察者对象
* @return mixed
*/
public function addObserver($key, Observer $observer);
/**
* @purpose: 从注册树中移除观察者
* @param string $key 给所添加的观察者的一个唯一 key,方便从注册树中移除观察者
* @return mixed
*/
public function removeObserver($key);
/**
* @purpose: 广播通知以注册的观察者
* @return mixed
*/
public function notify();
}
/**
* @purpose: 实现主体接口,主要就是添加观察者和广播通知观察者
* Class Action
*/
class Action implements Subject
{
/**
* @var array 保存所有已注册的观察者
*/
public $_observer = [];
/**
* @purpose: 添加观察者
* @param string $key 给所添加的观察者的一个唯一 key,方便从注册树中移除观察者
* @param Observer $observer 观察者对象
* @return mixed
*/
public function addObserver($key, Observer $observer)
{
$this->_observer[$key] = $observer;
}
/**
* @purpose: 从注册树中移除观察者
* @param string $key 给所添加的观察者的一个唯一 key,方便从注册树中移除观察者
* @return mixed
*/
public function removeObserver($key)
{
unset($this->_observer[$key]);
}
/**
* @purpose: 广播通知以注册的观察者,对注册树进行遍历,让每个对象实现其接口提供的操作
* @return mixed
*/
public function notify()
{
foreach ($this->_observer as $observer) {
$observer->eat();
}
}
}
代码二
<?php
/*
观察者接口
*/
interface InterfaceObserver
{
function onListen($sender, $args);
function getObserverName();
}
// 可被观察者接口
interface InterfaceObservable
{
function addObserver($observer);
function removeObserver($observer_name);
}
// 观察者抽象类
abstract class Observer implements InterfaceObserver
{
protected $observer_name;
function getObserverName()
{
return $this->observer_name;
}
function onListen($sender, $args)
{
}
}
// 可被观察类
abstract class Observable implements InterfaceObservable
{
protected $observers = array();
public function addObserver($observer)
{
if ($observer instanceof InterfaceObserver)
{
$this->observers[] = $observer;
}
}
public function removeObserver($observer_name)
{
foreach ($this->observersas $index => $observer)
{
if ($observer->getObserverName() === $observer_name)
{
array_splice($this->observers, $index, 1);
return;
}
}
}
}
// 模拟一个可以被观察的类
class A extends Observable
{
public function addListener($listener)
{
foreach ($this->observers as $observer)
{
$observer->onListen($this, $listener);
}
}
}
// 模拟一个观察者类
class B extends Observer
{
protected $observer_name = 'B';
public function onListen($sender, $args)
{
var_dump($sender);
echo "<br>";
var_dump($args);
echo "<br>";
}
}
// 模拟另外一个观察者类
class C extends Observer
{
protected $observer_name = 'C';
public function onListen($sender, $args)
{
var_dump($sender);
echo "<br>";
var_dump($args);
echo "<br>";
}
}
参考
www.cnblogs.com/chrdai/p/11184221....
本作品采用《CC 协议》,转载必须注明作者和本文链接