Listening to the Words

PHP设计模式之—观察者模式

观察者模式

观察者模式(Observer),当一个对象状态发生改变时,依赖它的对象全部收到通知,并自动更新

模式动机

观察者模式包含如下角色:
  Subject: 目标
  ConcreteSubject: 具体目标
  Observer: 观察者
  ConcreteObserver: 具体观察者

  • Subject(目标)(抽象类,方便扩展)将观察者对象存放在一个容器里,该类提供一些接口,例如增加观察者(addObserver),撤销观察者(detach),通知观察者(notify)

  • ConcreteSubject(具体类,继承被观察者抽象类) 存入需要通知的观察者,当观察者需要update时,调用notify方法

  • 抽象观察者(接口或抽象类)为具体的观察者提供更新的接口,当被观察者通知时进行update

  • 具体观察者(具体类,继承或实现抽象观察者) 实现抽象观察者的接口,自动update
<?php

//目标接口,定义观察目标要实现的方法
abstract class Subject{
   abstract function attach(Observer $observer);  //添加观察者
   abstract function detach(Observer $observer);  //去除观察者
   abstract function notify();  //满足条件时通知所有观察者修改
   abstract function condition($num); //发起通知的条件
}

//具体观察目标(地铁七号线列车)
class UndergroundLineSeven extends Subject{
    private $observers = array();
    //添加观察者(乘客)
    function attach(Observer $observer){
         $this->observers[] = $observer;
    }
    //移除观察者(乘客)
    function detach(Observer $observer){
         $key=array_search($observer, $this->observers);
         if($key !== false){  //注意不要写成!=,表达式0!=flase为flase
              unset($this->observers[$key]);
         }
    }
    //通知所有所有观察者修改(通知所有乘客)
    function notify(){
        foreach($this->observers as $observer){
            $observer->update();
        }
    }
    //发起通知的条件(每到一站地)
    function condition($num){
        if($num>100){
            $this->notify();
        }
    }
}

//抽象观察者接口,定义所有观察者共同具有的属性——执行修改(每个乘客的抽象行为)
abstract class Observer{
    abstract function update($notify_info = null);
}
//具体观察者类,实现抽象观察者接口

//乘客Anna
class AnnaObserver extends Observer{

    function update($notify_info){
        if($notify_info=='十字大街站'){
         return "我是安娜,我要在十字大街站下车"
        }else{
        return false;
        }
      }

}
class BillObserver extends Observer{

    function update($notify_info){
        if($notify_info=='十四大街站'){
         return "我是比尔,我要在十四大街站下车"
        }else{
        return false;
        }
      }
}


//测试
$observerA = new AnnaObserver();//安娜准备出门
$observerB = new BillObserver();//比尔准备出门
$concreteSubject = new UndergroundLineSeven();//出行方式是地铁七号线
$concreteSubject->attach($observerA);   //安娜上车
$concreteSubject->attach($observerB);   //比尔上车
$concreteSubject->condition(10);        //七号线到站广播

 ?>

形象化的场景是:
– 以运营地铁线路为实体目标
– 地铁司机不知道每个乘客目的地,但是他知道每站都通知广播notify()
– 每个乘客去目的不同,但是他们都会下车update(),他们是观察者对象,他们收到通知后会选择是否下车,但一定会被通知

点赞