上一篇我们在观察者模式中加入了事件,插件可以根据不同的事件来做不同的业务处理,基本上很简单,我们直接通过主体对象携带事件名称即可。
下面我们要实现的是,只有在知道具体事件后才去实例化绑定了此事件的插件。
下面是具体的实现:
<?php
/**
* Author: shanhuhai
* Date: 2017/8/28 21:26
* Mail: 441358019@qq.com
*/
class PluginA implements SplObserver {
public function update(\SplSubject $subject) {
if($subject->event == 'register') {
echo "Plugin A ".$subject->user['name'].' is registering.'.PHP_EOL;
}
}
}
class PluginB implements SplObserver {
public function update(\SplSubject $subject) {
if($subject->event == 'register'){
echo "Plugin B ".$subject->user['name'].' is registering.'.PHP_EOL;
}
if($subject->event == 'login') {
echo "Plugin B ".$subject->user['name']. ' is logining.'.PHP_EOL;
}
}
}
class Observer implements SplObserver {
private $config = [];
public function __construct($config) {
foreach ($config as $plugin => $events ) {
foreach ($events as $event) {
$this->config[$event][] = $plugin;
}
}
}
public function update(\SplSubject $subject) {
if(array_key_exists($subject->event, $this->config)) {
foreach ($this->config[$subject->event] as $plugin) {
$plugin = new $plugin();
$plugin->update($subject);
}
}
}
}
class User implements SplSubject {
public $event;
private $observers = [];
public $user=[];
public function register($name, $password){
$this->user['name'] = $name;
$this->user['password'] = $password;
$this->event = 'register';
$this->notify();
}
public function login($name, $password) {
$this->user['name'] = $name;
$this->user['password'] = $password;
$this->event = 'login';
$this->notify();
}
public function attach(\SplObserver $observer) {
//array_push($this->observers, $observer);
$this->observer = $observer;
}
public function detach(\SplObserver $observer) {
$this->observer = null;
}
public function notify(){
$this->observer->update($this);
}
}
//-- 实例化主体对象
$user = new User();
//-- end
//-- 配置插件
$config = [
'PluginA' => ['register' ],
'PluginB' => ['register', 'login'],
];
//-- end
//-- 注册插件
$observer = new Observer($config);
$user->attach($observer);
//-- end
//-- 执行主体的业务代码
$user->register('shanhuhai', '123456');
$user->login('shanhuhai', '123456');
跟上一篇的代码比较,我们增加了一个配置$config, 用来说明哪些插件类绑定了哪些事件。
还新增了一个类 Observer 实现了 SplObserver 接口,我们通过给这个类传入 $config 配置来绑定插件和事件的映射关系, 当在主体对象 User 中调用 notify 时,我们调用Observer 的 update, 这时可以根据之前绑定的插件与事件的映射关系来实例化相应的插件处理事件。
其实观察者模式还叫“发布/订阅模式”, 这跟消息队列中说的“发布/订阅”基本上是一个意思,我们在 $config 的配置说明了订阅关系,哪个插件订阅哪个事件,当被订阅的事件发生时这个插件就会收到消息。比如 PluginA 订阅了 register 事件,当主体对象中 指定的event 等于 register时, PluginA将会被实例化并接收到主体对象传过来的数据。
在实际应用情况中,插件应该在一个特定目录中,每个插件是一个文件,以上机制想要应用到你的项目中,还要根据实际情况做相应修改。
转载请注明:SuperIT » PHP设计模式之——用观察者模式实现事件绑定