设计模式——观察者

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。

我们在用美团App时经常出现用户登录时会弹出一个框告诉用户获得了一张优惠券,金额和使用规则会根据用户距离上次的登录时间和消费习惯来定。当我们经常使用时获得优惠券的概率就会少,优惠金额也会少。软件设计里把登录做为一个被观察的类(主题),把送优惠券做为一个观察类。当用户登录时通知送优惠券,为用增加一个优惠券。可以多个观察者,比如用户登录后会根据其消费习惯给他推荐相关的店铺的广告类。这里有一个广告类也可以定义成一个观察者。

具体代码:

1、定义一个Subject主题接口,所有被观察都都要实现此接口;


/**
 * file name: Subject.php
 * user : 良子
 * date : 2021-01-07
 */

namespace libs\observer;


interface Subject
{
    public function attach(Observer $observer);
    public function detach(Observer $observer);
    public function notify();
}

2、定义一个Observer观察者接口,所有观察都都要实现此接口;

/**
 * file name: Observer.php
 * user : 良子
 * date : 2021-01-07
 */

namespace libs\observer;


interface Observer
{
     public function update(Subject $subject);
}

3、定义一个用户类User,即被观察对象。包含用户登录,注册等信息

/**
 * file name: User.php
 * user : 良子
 * date : 2021-01-06
 */

namespace libs\observer;


class User implements Subject
{
    protected $_observers = [];
    //登录次数
    public $loginTimes = 0;
    //常购买的品类
    public $buyCategeory = [];

    public function login ($username, $passwd)
    {
        echo '验证逻辑……此处省略<br/>';
        echo '获取用户信息逻辑……此处省略<br/>';
        //假设获取用户近一个月内的登录次数
        $this->loginTimes = mt_rand(0, 100);
        //假设获取用户买得最多 品类
        $categeory = ['奶茶', '咖啡', '可乐','水','啤酒'];
        $buyCategeory = array_rand($categeory, 2);
        foreach ($buyCategeory as $value) {
            array_push($this->buyCategeory, $categeory[$value]);
        }
        return true;
    }


    public function attach (Observer $observer)
    {
        $this->_observers[] = $observer;
    }

    public function detach (Observer $observer)
    {
        $key = array_search($observer,$this->_observers, true);
        if($key){
            unset($this->_observers[$key]);
        }
    }

    public function notify ()
    {
        foreach ($this->_observers as $value) {
            $value->update($this);
        }
    }

}

4、定义一个用户登录后送优惠券的观察者对象ObLoginCoupon,在ObLoginCoupon里只需要引入Coupon类,如果Coupon类由其他同事编写,则可以不需要变动他人的代码;

/**
 * file name: Obloin.php
 * user : 良子
 * date : 2021-01-07
 */

namespace libs\observer;


class ObLoginCoupon implements Observer
{
    protected $couponObj = null;
    public function update (Subject $subject)
    {
        $this->couponObj = new Coupon();
        //根据用户登录次数送相应金额的优惠券
        $this->couponObj->giveCoupnByLoginTime($subject->loginTimes);
    }
}

coupon类

namespace libs\observer;


class Coupon
{
    public function giveCoupnByLoginTime($times)
    {
        if ($times<10) {
            echo '送10元优惠券<br/>';
        } else if($times>=10 && $times<30) {
            echo '送5元优惠券<br/>';
        } else {
            echo '送3元优惠券<br/>';
        }
    }

}

5、如果需要其它的观察者如推荐广告,则定义一个用户登录后推广告的观察者对象ObLoginAd,在ObLoginAd里只需要引入Ad类,如果Ad类由其他同事编写,则可以不需要变动他人的代码;

/**
 * file name: ObLoginAd.php
 * user : 良子
 * date : 2021-01-07
 */

namespace libs\observer;


class ObLoginAd implements Observer
{

    public function update (Subject $subject)
    {
        $adObj = new Ad();
        //根据用户购买习惯推送相应的商品
        $adObj->getDataByCategory($subject->buyCategeory);
    }
}

Ad类

/**
 * file name: Login.php
 * user : 良子
 * date : 2021-01-06
 */

namespace libs\observer;

class Ad
{
    public function getDataByCategory($categorys)
    {
        echo '常买品类:'.implode(',', $categorys);
    }

}

客户端在调用户登录时的代码

/**
 * file name: observer.php
 * user : 良子
 * date : 2021-01-06
 */

require_once ('./libs/loader/Loader.php');
spl_autoload_register('\\libs\\loader\\Loader::autoload');

$username = '张三';
$passwd = '123456';

$userObj = new \libs\observer\User();

$isLogin = $userObj->login($username, $passwd);

if ($isLogin) { //登录成功
    $obLoginCouponObj = new \libs\observer\ObLoginCoupon();
    $obLoginAdObj = new \libs\observer\ObLoginAd();
    //添加送优惠券的观察者
    $userObj->attach($obLoginCouponObj);
    //添加广告观察者
    $userObj->attach($obLoginAdObj);
    //继续添加其它观察者
    $userObj->notify();
    //具体操作

} else {
    //具体操作
}

以上就是一个简单的观察者模式。

大家结合之前所说的单例模式,可以将Coupon和Ad进行改写。让项目更加高效!

图片

关注快乐程序员公众号,每日分享一点小知识。爱编程,爱生活!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值