php设计模式入门-观察者模式

来源:互联网 发布:淘宝联盟推广位爱分享 编辑:程序博客网 时间:2024/05/16 15:04

场景:一个气象站点,当温度、湿度或气压发生改变时都要像订阅了该气象服务的用户推送提醒,假设用户拥有三种电子产品:mac、iphone和apple watch。

第一版的设计代码如下:


WeatherData.php

<?php/** * 气象站类,用于提供气象数据,数据变化时及时推送至用户的设备 *  * @author ben * */class WeatherData{/** * 气温 * @var string */private $_temperature;/** * 气压 * @var string */private $_pressure;/** * 湿度 * @var string */private $_humidity;/** * 用户设备之mac * @var object */private $_mac;/** * 用户设备之iphone * @var object */private $_iphone;/** * 用户设备之watch(壕啊,咱们做朋友吧。。。) * @var object */private $_iwatch;/** * 初始化用户设备 * @param object $mac * @param object $iphone * @param object $iwatch */public function __construct($mac, $iphone, $iwatch){$this->_mac = $mac;$this->_iphone = $iphone;$this->_iwatch = $iwatch;}/** * 当数据变更时向用户推送即时数据 */public function dataChanged(){$this->_temperature = $this->getTemperature();$this->_humidity = $this->getHumidity();$this->_pressure = $this->getPressure();$this->_mac->update($this->_humidity, $this->_temperature, $this->_pressure);$this->_iphone->update($this->_humidity, $this->_temperature, $this->_pressure);$this->_iwatch->update($this->_humidity, $this->_temperature, $this->_pressure);}}

代码的坏味道:

气象站类WeatherData与用户的设备类mac、iphone、iwatch类之间存在着强耦合关系,而真实的场景中用户可能随时会取消业务,或者为新的电子产品订阅该业务,这就意味着我们今后将会频繁的修改这个文件中的代码。

下面我们来看看观察者模式是怎么为我们解决这个难题的。

要理解观察者模式,可以结合真实的案例,比如说订阅报纸,仔细想想在这样的场景中存在哪几种元素:

1、报纸的发布者;

2、报纸的订阅者;

发布者与订阅者组成了观察者的两个基本要素。具体用uml类图描述如下:


具体的实现代码:

Subject.php

<?phpabstract class Subject{protected $observers;public function addObserver($key, Equipment $observer){$this->observers[$key] = $observer;}public function removeObserver($key){if(isset($this->observers[$key])){unset($this->observers[$key]);}}abstract function notify();// foreach ($this->observer as $observer){// $observer->update();// }}

Equipment.php

<?phpabstract class Equipment{abstract function update($temperature, $pressure, $humidity);abstract function display();}
WeatherData.php

<?phprequire_once 'Subject.php';class WeatherData extends Subject{private $_temperature;private $_pressure;private $_humidity;/* (non-PHPdoc) * @see Subject::notify() */public function notify() {foreach ($this->observers as $observer){$observer->update($this->_temperature, $this->_pressure, $this->_humidity);}}public function dataChange($temperature, $pressure, $humidity){$this->_temperature = $temperature;$this->_pressure = $pressure;$this->_humidity = $humidity;$this->notify();}}

Mac.php

<?phprequire_once 'Equipment.php';class Mac extends Equipment{private $_temperature;private $_pressure;private $_humidity;/* (non-PHPdoc) * @see Equipment::update() */public function update($temperature, $pressure, $humidity) {// TODO Auto-generated method stub$this->_temperature = $temperature;$this->_pressure = $pressure;$this->_humidity = $humidity;$this->display();}/* (non-PHPdoc) * @see Equipment::display() */public function display() {// TODO Auto-generated method stubecho "Current conditions:<br />temperature:$this->_temperature;<br />pressure:$this->_pressure;<br />humidity:$this->_humidity;<br />    --From Mac client<br />";}}

Iwatch.php

<?phprequire_once 'Equipment.php';class Iwatch extends Equipment{private $_temperature;private $_pressure;private $_humidity;/* (non-PHPdoc) * @see Equipment::update() */public function update($temperature, $pressure, $humidity) {// TODO: Auto-generated method stub$this->_temperature = $temperature;$this->_pressure = $pressure;$this->_humidity = $humidity;$this->display();}/* (non-PHPdoc) * @see Equipment::display() */public function display() {// TODO Auto-generated method stubecho "Current conditions:<br />temperature:$this->_temperature;<br />pressure:$this->_pressure;<br />humidity:$this->_humidity;<br />    --From Iwatch client<br />";}}
Iphone.php

<?phprequire_once 'Equipment.php';class Iphone extends Equipment{private $_temperature;private $_pressure;private $_humidity;/* (non-PHPdoc) * @see Equipment::update() */public function update($temperature, $pressure, $humidity) {// TODO Auto-generated method stub$this->_temperature = $temperature;$this->_pressure = $pressure;$this->_humidity = $humidity;$this->display();}/* (non-PHPdoc) * @see Equipment::display() */public function display() {// TODO Auto-generated method stubecho "Current conditions:<br />temperature:$this->_temperature;<br />pressure:$this->_pressure;<br />humidity:$this->_humidity;<br />    --From Iphone client<br />";}}
index.php

<?phprequire_once 'WeatherData.php';require_once 'Iwatch.php';require_once 'Iphone.php';require_once 'Mac.php';$subject = new WeatherData();$observer1 = new Iwatch();$observer2 = new Iphone();$observer3 = new Mac();$subject->addObserver('Iwatch', $observer1);$subject->addObserver('Iphone', $observer2);$subject->addObserver('Mac', $observer3);$subject->dataChange('38摄氏度', '气压好高啊', '很湿润');

运行结果是:

Current conditions:temperature:38摄氏度;pressure:气压好高啊;humidity:很湿润;    --From Iwatch clientCurrent conditions:temperature:38摄氏度;pressure:气压好高啊;humidity:很湿润;    --From Iphone clientCurrent conditions:temperature:38摄氏度;pressure:气压好高啊;humidity:很湿润;    --From Mac client


当然php已经帮我们准备好了两个接口,我们没有必要重造轮子,这两个接口分别是SplObserver和SplSubject,关于这两个接口的定义,可以查看以下官方文档:

SplObserver:http://php.net/manual/zh/class.splobserver.php

SplSubject:http://php.net/manual/zh/class.splsubject.php

使用这两个接口之后我们进一步修改后的代码清单如下:

index.php

<?phprequire_once 'WeatherData.php';require_once 'Iwatch.php';require_once 'Iphone.php';require_once 'Mac.php';$subject = new WeatherData();$observer1 = new Iwatch();$observer2 = new Iphone();$observer3 = new Mac();$subject->attach($observer1);$subject->attach($observer2);$subject->attach($observer3);$subject->dataChange('38摄氏度', '气压好高啊', '很湿润');


Iphone.php

<?phpclass Iphone implements SplObserver{private $_temperature;private $_pressure;private $_humidity;/* (non-PHPdoc) * @see Equipment::update() */public function update(SplSubject $subject) {// TODO Auto-generated method stub$this->_temperature = $subject->getTemperature();$this->_pressure = $subject->getPressure();$this->_humidity = $subject->getHumidity();$this->display();}/* (non-PHPdoc) * @see Equipment::display() */public function display() {// TODO Auto-generated method stubecho "Current conditions:<br />temperature:$this->_temperature;<br />pressure:$this->_pressure;<br />humidity:$this->_humidity;<br />    --From Iphone client<br />";}}


Iwatch.php

<?phpclass Iwatch implements SplObserver{private $_temperature;private $_pressure;private $_humidity;/* (non-PHPdoc) * @see Equipment::update() */public function update(SplSubject $subject) {// TODO Auto-generated method stub$this->_temperature = $subject->getTemperature();$this->_pressure = $subject->getPressure();$this->_humidity = $subject->getHumidity();$this->display();}/* (non-PHPdoc) * @see Equipment::display() */public function display() {// TODO Auto-generated method stubecho "Current conditions:<br />temperature:$this->_temperature;<br />pressure:$this->_pressure;<br />humidity:$this->_humidity;<br />    --From Iwatch client<br />";}}



Mac.php

<?phpclass Mac implements SplObserver{private $_temperature;private $_pressure;private $_humidity;/* (non-PHPdoc) * @see Equipment::update() */public function update(SplSubject $subject) {// TODO Auto-generated method stub$this->_temperature = $subject->getTemperature();$this->_pressure = $subject->getPressure();$this->_humidity = $subject->getHumidity();$this->display();}/* (non-PHPdoc) * @see Equipment::display() */public function display() {// TODO Auto-generated method stubecho "Current conditions:<br />temperature:$this->_temperature;<br />pressure:$this->_pressure;<br />humidity:$this->_humidity;<br />    --From Mac client<br />";}}
WeatherData.php

<?phpclass WeatherData implements SplSubject{protected $observers;private $_temperature;private $_pressure;private $_humidity;/* (non-PHPdoc) * @see Subject::notify() */public function notify() {foreach ($this->observers as $observer){$observer->update($this);}}public function dataChange($temperature, $pressure, $humidity){$this->_temperature = $temperature;$this->_pressure = $pressure;$this->_humidity = $humidity;$this->notify();}public function getTemperature(){return $this->_temperature;}public function getPressure(){return $this->_pressure;}public function getHumidity(){return $this->_humidity;}/* (non-PHPdoc) * @see SplSubject::attach() */public function attach(SplObserver $observer) {// TODO Auto-generated method stub$this->observers[] = $observer;}/* (non-PHPdoc) * @see SplSubject::detach() */public function detach(SplObserver $observer) {// TODO Auto-generated method stub$key = array_search($observer, $this->observers, true);if($key){unset($this->observers[$key]);}}}



0 0
原创粉丝点击