设计模式 - 观察者模式

简介

场景

如果想实时跟踪某个对象的状态(例如,对于负责下载的对象,想实时跟踪下载进度),有两种方法:

  • 定时轮询:定时访问目标对象的接口,获取其当前状态
  • 主动通知:在目标对象发生变化时,主动通知需要知道这个变化的对象

模式定义

观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得当一个对象状态发生改变时,所有依赖它的对象将自动得到通知和更新。

观察者模式又叫做发布-订阅(Publish/Subscribe)模式。

模式特点

观察者模式包含四个角色,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系:

  • Subject:观察对象
  • ConcreteSubject:具体观察对象
  • Observer:观察者
  • ConcreteObserver:具体观察者

这里写图片描述

优缺点

  • 观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。
  • 观察者模式在观察目标和观察者之间建立松耦合,可以独立改变目标或观察者
  • 观察者自己觉得是否订阅通知,目标对象对此一无所知
  • 新增监控要求时,大型的单体设计不能很好地扩展

PHP 代码示例

AbstractObserver 是观察者抽象类,其中定义了用来被观察目标调用的 update() 方法。AbstractSubject 是观察目标抽象类,其中定义了用来添加观察者的 attach() 方法,用来删除观察者的 detach() 方法,用于通知所有观察者的 notify() 方法。

<?php

abstract class AbstractObserver {
    abstract function update(AbstractSubject $subject_in);
}

abstract class AbstractSubject {
    abstract function attach(AbstractObserver $observer_in);
    abstract function detach(AbstractObserver $observer_in);
    abstract function notify();
}

class PatternObserver extends AbstractObserver {
    public function update(AbstractSubject $subject) {
      writeln(' new favorite patterns: '.$subject->getFavorites());    
    }
}

class PatternSubject extends AbstractSubject {
    private $favoritePatterns = NULL;
    private $observers = array();
    function attach(AbstractObserver $observer_in) {
      $this->observers[] = $observer_in;
    }
    function detach(AbstractObserver $observer_in) {
      //$key = array_search($observer_in, $this->observers);
      foreach($this->observers as $okey => $oval) {
        if ($oval == $observer_in) { 
          unset($this->observers[$okey]);
        }
      }
    }
    function notify() {
      foreach($this->observers as $obs) {
        $obs->update($this);
      }
    }
    function updateFavorites($newFavorites) {
      $this->favorites = $newFavorites;
      $this->notify();
    }
    function getFavorites() {
      return $this->favorites;
    }
}

function writeln($line_in) {
    echo $line_in."<br/>".PHP_EOL;
}

  writeln('BEGIN TESTING OBSERVER PATTERN');
  writeln('');

  $subject= new PatternSubject();
  $observer= new PatternObserver();
  $subject->attach($observer);
  $subject->updateFavorites('abstract factory, decorator, visitor');
  $subject->updateFavorites('abstract factory, observer, decorator');
  $subject->detach($observer);
  $subject->updateFavorites('abstract factory, observer, paisley');

  writeln('END TESTING OBSERVER PATTERN');

posted on 2018-07-02 22:31  kikajack  阅读(124)  评论(0编辑  收藏  举报