php设计模式入门-观察者模式
2015-04-12 21:08
801 查看
场景:一个气象站点,当温度、湿度或气压发生改变时都要像订阅了该气象服务的用户推送提醒,假设用户拥有三种电子产品:mac、iphone和apple watch。
第一版的设计代码如下:
WeatherData.php
代码的坏味道:
气象站类WeatherData与用户的设备类mac、iphone、iwatch类之间存在着强耦合关系,而真实的场景中用户可能随时会取消业务,或者为新的电子产品订阅该业务,这就意味着我们今后将会频繁的修改这个文件中的代码。
下面我们来看看观察者模式是怎么为我们解决这个难题的。
要理解观察者模式,可以结合真实的案例,比如说订阅报纸,仔细想想在这样的场景中存在哪几种元素:
1、报纸的发布者;
2、报纸的订阅者;
发布者与订阅者组成了观察者的两个基本要素。具体用uml类图描述如下:
具体的实现代码:
Subject.php
Equipment.php
Mac.php
Iwatch.php
运行结果是:
当然php已经帮我们准备好了两个接口,我们没有必要重造轮子,这两个接口分别是SplObserver和SplSubject,关于这两个接口的定义,可以查看以下官方文档:
SplObserver:http://php.net/manual/zh/class.splobserver.php
SplSubject:http://php.net/manual/zh/class.splsubject.php
使用这两个接口之后我们进一步修改后的代码清单如下:
index.php
Iphone.php
Iwatch.php
Mac.php
第一版的设计代码如下:
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
<?php abstract 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
<?php abstract class Equipment{ abstract function update($temperature, $pressure, $humidity); abstract function display(); }WeatherData.php
<?php require_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
<?php require_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 stub echo "Current conditions:<br /> temperature:$this->_temperature;<br /> pressure:$this->_pressure;<br /> humidity:$this->_humidity;<br /> --From Mac client<br />"; } }
Iwatch.php
<?php require_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 stub echo "Current conditions:<br /> temperature:$this->_temperature;<br /> pressure:$this->_pressure;<br /> humidity:$this->_humidity;<br /> --From Iwatch client<br />"; } }Iphone.php
<?php require_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 stub echo "Current conditions:<br /> temperature:$this->_temperature;<br /> pressure:$this->_pressure;<br /> humidity:$this->_humidity;<br /> --From Iphone client<br />"; } }index.php
<?php require_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 client Current conditions: temperature:38摄氏度; pressure:气压好高啊; humidity:很湿润; --From Iphone client Current 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
<?php require_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
<?php class 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 stub echo "Current conditions:<br /> temperature:$this->_temperature;<br /> pressure:$this->_pressure;<br /> humidity:$this->_humidity;<br /> --From Iphone client<br />"; } }
Iwatch.php
<?php class 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 stub echo "Current conditions:<br /> temperature:$this->_temperature;<br /> pressure:$this->_pressure;<br /> humidity:$this->_humidity;<br /> --From Iwatch client<br />"; } }
Mac.php
<?php class 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 stub echo "Current conditions:<br /> temperature:$this->_temperature;<br /> pressure:$this->_pressure;<br /> humidity:$this->_humidity;<br /> --From Mac client<br />"; } }WeatherData.php
<?php class 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]); } } }
相关文章推荐
- PHP 设计模式之观察者模式
- php设计模式之观察者模式
- php八大设计模式之观察者模式
- PHP设计模式:观察者模式
- PHP 设计模式之观察者模式
- PHP设计模式 观察者设计模式
- PHP设计模式7-观察者模式
- PHP设计模式之观察者模式
- PHP设计模式实例之(观察者模式、策略模式、简单工厂模式)
- PHP模式设计----观察者模式(Observer)
- PHP设计模式-观察者
- PHP设计模式系列 - 观察者模式
- PHP 设计模式之观察者模式
- PHP设计模式之观察者模式实例
- 设计模式入门-装饰器模式(php版)
- php核心学习-设计模式的学习-观察者模式
- [php]php设计模式 Observer(观察者模式)
- php设计模式之观察者模式
- PHP设计模式之观察者模式
- php设计模式-观察者模式