先来看个例子:
class Video {
public function new(){
$checkNewVideo = Video::find()->where("xxxxx")->one();
if($checkNewVideo){
// 通知各位
LaoWang::newVideo();
XiaoLi::newVideo();
ChuanPu::newVideo();
.......
// 还有很多很多,比如在给某个集体客户群发、短信发等等等等
}
}
}
// 具体实现
$model = new Video();
$model->new()
其实,在系统小的时候,这是非常快捷有效的方式。
但是,当系统变大的时候,这种方法马上面临难以扩展的问题,并且容易出错。
这两个对象的耦合度太高了。
我们先改进上面的代码,观察者模式
/**
* 被观察者接口
* 定义了一些公用方法声明,使用观察者模式的类都可以继承此接口
*/
interface Observable {
// 添加/注册观察者
public function attach(Observer $observer);
// 删除观察者
public function detach(Observer $observer);
// 触发通知
public function notify();
}
class Video implements Observable {
public $observers = [];// 订阅者
// 添加观察者
public function attach(Observer $observer){
$key = array_search($observer, $this->observers);
if ($key === false) {
$this->observers[] = $observer;
}
}
// 删除观察者
public function detach(Observer $observer){
$key = array_search($observer, $this->observers);
if ($key !== false) {
unset($this->observers[$key]);
}
}
// 通知所有观察者
public function notify(){
foreach ($this->observers as $observer) {
// 把本类对象传给观察者
$observer->update($this);
}
}
public function new(){
$checkNewVideo = Video::find()->where("xxxxx")->one();
if($checkNewVideo){
$this->notify();
}
}
}
你看到了,修改后的代码并不关心具体发送给谁,它只是遍历了所有观察者的列表,然后告诉他们一下而已,观察者增减对此类不会有任何影响。
对于观察者,数字不定,随时有增减,因此我们定义了一个观察者接口开始抽象它们。
/**
* 观察者接口
*/
interface Observer
{
// 接收到通知的处理方法
public function update(Observable $observable);
}
class LaoWang implements Observer {
public function update(Observable $observable){
echo "立刻开始看视频";
}
}
class XiaoMing implements Observer {
public function update(Observable $observable){
echo "收到后忽略通知";
}
}
class ChuanPu implements Observer {
public function update(Observable $observable){
echo "收藏了一下,然后去wc看";
}
}
class BingBing implements Observer {
public function update(Observable $observable){
echo "立刻开始看视频";
}
}
$model = new Video();
$model->attach(new LaoWang());
$model->attach(new XiaoLi());
$model->attach(new ChuanPu());
$model->attach(new BingBing());
$model->new();
上面就是观察者模式,我们先预想一下我们的事件,假设我们定义了很多观察者代码,他们监听事件的发生,当一个事件被触发,这些观察者都会知道,执行各自的逻辑。
事件就是观察者模式的一种应用。
监听系统的某一个行为,实时获取并执行自己负责的代码。
yii事件案例:
- 本地留一个log
- 告诉登陆者的朋友它登陆了
- 发送一个邮件给管理员
class UserController extends Controller {
public function actionIndex(){
// 这里有一些代码.....
Yii::$app->user->login($user);
// todo 登陆后要做的事情
}
}
// OLog app\models\OLog.php
class OLog {
static public function add($event){
echo "我记录了一条登陆记录";
}
}
// Admin app\models\Admin.php
class Admin {
static public function sendMail($event){
echo "我给管理员发了邮件";
}
}
// User app\models\User.php
class User {
static public function notifyFirend($event){
echo "告诉了朋友们我登陆了";
}
}
class UserController extends Controller {
// 定义事件名字
const EVENT_USER_LOGIN = 'user_login';
public function __construct(){
// 绑定事件
$this->on(self::EVENT_USER_LOGIN,['app\models\OLog','add']);
$this->on(self::EVENT_USER_LOGIN,['app\models\Admin','sendMail']);
$this->on(self::EVENT_USER_LOGIN,['app\models\User','notifyFirend']);
}
public function actionIndex(){
.....
// login
}
}
use app\events\UserLoginEvent;
class UserController extends Controller {
.......
.......
public function actionIndex(){
// 这里有一些代码.....
Yii::$app->user->login($user);
$event = new UserLoginEvent();
$event->userId = $user->id;
$this->trigger(self::EVENT_USER_LOGIN,$event);
}
}
// event/UserLoginEvent.php
namespace app\events;
use yii\base\Event;
class UserLoginEvent extends Event {
public $userId = 0;
}
app\controllers\UserController.php
use app\events\UserLoginEvent;
class UserController extends Controller {
.......
.......
public function actionIndex(){
// 这里有一些代码.....
Yii::$app->user->login($user);
$event = new UserLoginEvent();
$event->userId = $user->id;
$this->trigger(self::EVENT_USER_LOGIN,$event);
}
}
// User app\models\User.php
class User {
static public function notifyFirend($event){
$userId = $event->userId;
echo "告诉了朋友们我登陆了";
}
}