编程中的那些套路——关于观察者模式

该文章属于《编程中的那些经典套路——设计模式汇总》系列,而且如下内容基于语言PHPphp

今天咱们来谈谈观察者模式,这是一个常常用到的设计模式。sql

让咱们想象一个场景:一个网站有不一样等级区域的用户,不一样等级的的用户登陆后能够得到对应的服务(一级用户登陆后得到一级服务,二级用户登陆后得到二级服务,…以此类推)。那么咱们如何写这段业务逻辑呢?编程

按照通常思路:咱们会写N个if..else判断,像下面这样:segmentfault

//登陆操做..省略
 
if(一级用户) {
 
echo ' 一级服务';
 
} else if(二级用户){
 
echo '二级服务';
 
} else if(三级用户){
 
echo '三级服务';
 
}

但这样写代码有一个弊端,若是咱们又增长了一个等级用户,那么咱们是否是要修改原来的代码呢(增长多一个if..else判断),这样作是很是不稳当的,由于写好的代码咱们不该该碰它。设计模式

咱们应该写一段拓展性强与维护性较强的代码,由此衍生出观察者模式。数组

观察者模式的大体思路是这样的:有一个观察者列表(A),有一个被观察者列表(B),当B发生变化时,程序就会遍历观察者列表A,随之执行对应的update操做,而后得到想要的效果。语言表述可能比较难以理解,咱们来看代码吧。网站

PHP已经帮咱们内置了一个观察者模式的接口(The SplSubject interface),咱们能够直接实现这个接口:this

图片描述
而且php还提供了一个存储对象的class(即观察者列表):spa

图片描述

固然咱们彻底能够不使用这个类,能够用数组代替。设计

具体代码:

观察者模式.php

<?php
 
//LoginSubject
 
class LoginSubject implements SplSubject{
 
    //观察者列表
 
    public $observers,$value,$hobby,$address;
 
    //初始化变量
 
    public function __construct(){
 
        //sqlObjectStorage是一个类,专门用来存储内容,观察者列表就是存在此类
 
        $this->observers = new SplObjectStorage();
 
    }
 
    //登陆
 
    public function login(){
 
        //登陆过程,省略
 
        $this->notify();
 
    }
 
    //添加观察者
 
    public function attach(SplObserver $observer){
 
        $this->observers->attach($observer);
 
    }
 
    //剔除观察者
 
    public function detach(SplObserver $observer){
 
        $this->observers->detach($observer);
 
    }
 
    //登录后通知notify
 
    public function notify(){
 
        $observers = $this->observers;
 
        //这段rewind不可或缺... 将节点指针指向第一位节点
 
        $observers->rewind();
 
        //当前节点存在
 
            while($observers->valid()){
 
                $observer = $observers->current();//获取当前节点(即观察者)
 
                $observer->update($this);//进行update犯法操做
 
                $observers->next();//next 节点
 
            }
 
    }
 
}
 
//observer User1Observers
 
class User1Observers implements SplObserver {
 
    public function update(SplSubject $subject){
 
        echo '我是一级用户,请给我对应的一级服务';
 
    }
 
}
 
//observer User2Observers
 
class User2Observers implements SplObserver {
 
    public function update(SplSubject $subject){
 
        echo '我是二级用户,请给我对应的二级服务';
 
    }
 
}
 
//observer CommenUserObservers
 
class CommenUserObservers implements SplObserver {
 
    public function update(SplSubject $subject){
 
        echo '我是普通用户,请给我对应的普通服务';
 
    }
 
}
 
//若是须要的话能够继续增长或者减小用户等级,丝绝不会影响本来的等级用户
 

 
$subject = new LoginSubject();
 
$CommenUserObservers = new CommenUserObservers;//普通用户
 
$subject->attach(new User1Observers);//增长观察者:一级用户
 
$subject->attach(new User2Observers);//增长观察者:二级用户
 
$subject->attach($CommenUserObservers);//增长观察者:普通用户
 
$subject->login();//登陆,触发notify
 
//output:我是一级用户,请给我对应的一级服务我是二级用户,请给我对应的二级服务我是普通用户,请给我对应的普通服务
 
echo '<br/>';
 
//若是有一天普通用户压根没有对应的服务了,那么咱们就能够剔除它了
 
//$subject->detach(new CommenUserObservers); 无效
 
$subject->detach($CommenUserObservers);//删除观察者:普通用户
 
$subject->login();//登陆,触发notify,普通用户就不会被通知啦
 
//output:我是一级用户,请给我对应的一级服务我是二级用户,请给我对应的二级服务
 
?>

看出门道了吗?每当登陆操做的时候,就会顺带触发notify方法,从而遍历关注者列表内的对象方法update,从而达到不一样的用户得到不一样的服务目的,而当咱们须要新增/减小用户等级的时候又不须要修改源代码,很好的符合了开放封闭原则。

我一直认为观察者模式单例模式工厂模式三者都是很棒的设计模式,但观察者模式理解起来稍微比较困难,若是有困惑的话能够直接在评论区发问。

该文章属于《编程中的那些经典套路——设计模式汇总》系列

相关文章
相关标签/搜索