PHP设计模式--观察者模式

54 阅读2分钟
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>观察</title>
</head>
<style>
    div{
        width: 80%;
        height: 300px;
        border: 1px solid blue;
        margin: 10px;
    }
</style>
<body>
<select name="sel" id="sel">
    <option value="0">男士广告</option>
    <option value="1">女士广告</option>
</select>
<input  type="button" onclick="drop()" value="不再观察购物频道">
<div id="test2">新闻</div>
<div id="test3">购物</div>
</body>

<script>
    var sel = document.getElementById('sel');
    sel.observers = [];
    sel.attach = function (obj){
        sel.observers[this.observers.length] = obj;
    }
    sel.detach = function (obj){
        for (var i=0;i < this.observers.length; i++){
            if(this.observers[i] === obj){
                delete this.observers[i];
            }
        }
    }

    sel.onchange = sel.notify = function (){
        for (var i=0;i < this.observers.length;i++){
            if(this.observers[i]){
                this.observers[i].update(this);
            }
        }
    }

    var test2 = document.getElementById('test2');
    var test3 = document.getElementById('test3');

    sel.attach(test2);
    sel.attach(test3);

    test2.update = function (sel){
        if(sel.value=='1'){
            this.innerHTML = '明星八卦';
        }else if(sel.value=='0'){
            this.innerHTML = '德国足球';
        }
    }

    test3.update = function (sel){
        if(sel.value=='1'){
            this.innerHTML = '化妆品护肤品';
        }else if(sel.value=='0'){
            this.innerHTML = '大众汽车';
        }
    }

     function drop (){
        sel.detach(test3)
    }




</script>
</html>

上述点击选择按钮,下面的方块显示对应的内容,当然也可以选择不再观察其中的某个方块对象

<?php
interface Observer{
    public function update($data);
}

class Message implements Observer{
    public function update($data)
    {
        // TODO: Implement update() method.
        echo '发送短信通知变化'.$data['uid'];
    }
}

class Goods implements Observer{
    public function update($data)
    {
        // TODO: Implement update() method.
        echo '修改商品库存'.$data['goods_id'];
    }
}

class Order{
    protected $observers = [];

    public $data = [];

    public function __construct($uid,$goods_id){
        $this->data = [
            'uid'=>$uid,
            'goods_id'=>$goods_id
        ];
    }

    public function attach($obj){
        $this->observers[] = $obj;
    }

    public function detach($obj){
        foreach ($this->observers as $k=>$v){
            if($v===$obj){
                unset($this->observers[$k]);
            }
        }
    }

    public function notify(){
        foreach ($this->observers as $obj){
            $obj->update($this->data);
        }
    }
}

$message = new Message();
$goods = new Goods();

$order = new Order('4444','1128');
$order->attach($message);
$order->attach($goods);


$order->notify();

$order->detach($message);

$order->notify();

Order的实现类,只是更新了状态,在这个状态发生改变的时候,调用观察者遍历的方法进行所有观察的update()操作

  • 观察者,其实就是自身做了一个更新(update),而Order,可以批量的执行观察者,请注意,我们不需要去修改目标类中的任何代码,只需要从外部添加就可以了,所以就让目标和观察者解耦互相之间不用关心对方的情况了
  • 观察者可以记录目标的状态,也可以不用记录,比如我们发完短信后的数据库更新或者插入操作,只有短信接口发送成功后我们再修改短信数据的状态就可以了,不一定完全需要将目标的发送状态传送给观察者
  • 当一个类在发生改变时,不知道可能会对其他多少类产生影响,这个时候观察者非常有用
  • 观察者模式中还是存在着耦合,那就是目标类中有一个观察者对象列表,如果观察者没有实现update()方法,那么就会出现问题