摘要:這是一個設計模式系列本書所有案例均來自設計模式中文版地址歡迎大家觀察者模式定義了對象之間的一對多依賴當一個對象改變狀態時它的所有依賴者都將會收到通知并自動更新觀察者模式形容圖設計謎題有一個氣象觀察站我們希望建立一個應用有三種布告板用于顯示
觀察者模式這是一個設計模式系列,本書所有案例均來自「Head-First設計模式(中文版)」, Github地址, 歡迎大家 watch, star
定義了對象之間的一對多依賴,當一個對象改變狀態時,它的所有依賴者都將會收到通知并自動更新.
觀察者模式形容圖
設計謎題有一個氣象觀察站,我們希望建立一個應用,有三種布告板(用于顯示不同的氣象數據),當氣象站獲取到最新的測量數據時,我們希望三種布告板能實時更新.
類圖設計
其中 WeatherData用于獲取氣象站最新測量數據(三個get方法),當數據更新時,會調用onChanged方法(不要管為什么,這是氣象站內部邏輯).
代碼實現
主題接口
interface Sublect { public function registerObserver(Observer $observer); public function removeObserver(); public function nitifyObservers(); }
主題對象 WeatherData
class WeatherData implements Sublect { protected $observers = []; protected $pressure, $temperature, $humidity; public function registerObserver(Observer $observer) { if (array_search($observer, $this->observers) === false) { $this->observers[] = $observer; } } public function removeObserver() { if (($index = array_search($observer, $this->observers)) !== false) { unset($this->observers[$index]); } } public function nitifyObservers() { foreach ($this->observers as $observer) { $observer->update($this->getPressure(), $this->getTemperature(), $this->getHumidity()); } } public function onChanged() { $this->nitifyObservers(); } //獲取最新氣壓 public function getPressure() { return $this->pressure; } //獲取最新溫度 public function getTemperature() { return $this->temperature; } //獲取最新濕度 public function getHumidity() { return $this->humidity; } //測試 public function youNeedChanged() { $this->pressure = mt_rand(1, 99); $this->temperature = mt_rand(1, 99); $this->humidity = mt_rand(1, 99); $this->onChanged(); } }
觀察者接口
interface Observer { //氣壓/溫度/濕度 public function update($pressure, $temperature, $humidity); }
顯示面板接口
interface DisplayElement { public function display(); }
觀察者對象集
class CurrentConditionsDisplay implements Observer, DisplayElement { protected $subject; protected $pressure, $temperature, $humidity; //這里為什么會保留 Subject 接口的引用是為了方便的 remove 及 registe public function __construct(Sublect $subject) { $this->subject = $subject; $this->subject->registerObserver($this); } public function update($pressure, $temperature, $humidity) { $this->pressure = $pressure; $this->temperature = $temperature; $this->humidity = $humidity; $this->display(); } public function display() { echo "Current pressure: {$this->pressure}, Current temperature: {$this->temperature}"; } } //其他兩種布告板省略
測試
$weatherData = new WeatherData(); $display = new CurrentConditionsDisplay($weatherData);//把當前布告欄注冊成為觀察者 //$other = new OthersDisplay($weatherData);//把當前布告欄注冊成為觀察者 //$other = new OtherDisplay($weatherData);//把當前布告欄注冊成為觀察者 $weatherData->youNeedChanged();//氣象站數據更新了會導致布告板實時更新 //Current pressure: 33, Current temperature: 46另一種形式的觀察者模式
我們知道,觀察者總是被動的接受主題對象的推送,但有些場景下,我們希望觀察者能主動的去獲取數據;畢竟觀察者數量這么多,主題對象不可能事先知道每個觀察者需要的狀態,并且也不會導致明明只需要一點點數據,卻被迫收到一堆.
我們來重寫設計上面的問題.
類圖基本保持不變,只是在WeatherData類新增了setChanged方法并改變了Observer接口update簽名.
重構后的主題接口
interface Sublect { public function registerObserver(Observer $observer); public function removeObserver(); public function nitifyObservers($args = null); } interface Observer { public function update(Sublect $subject, $object = null); }
重構后的主題對象
class WeatherData implements Sublect { protected $observers = []; protected $pressure, $temperature, $humidity, $changed; public function nitifyObservers($args = null) { if ($this->changed) { foreach ($this->observers as $observer) { $observer->update($this, $args); } $this->changed = false; } } public function onChanged() { $this->setChanged(); $this->nitifyObservers([ "pressure" => $this->pressure, "temperature" => $this->temperature, "humidity" => $this->humidity, ]); } public function setChanged()//新增方法 { $this->changed = true; } //其他方法保持不變 }
重構后的布告板對象
class CurrentConditionsDisplay implements Observer, DisplayElement { protected $subject; protected $pressure, $temperature, $humidity; //這里為什么會保留 Subject 接口的引用是為了方便的 remove 及 registe public function __construct(Sublect $subject) { $this->subject = $subject; $this->subject->registerObserver($this); } public function update(Sublect $subject, $object = null) { if ($subject instanceof Sublect) { //你可以用 拉取 的形式獲取最新數據 $this->pressure = $subject->getPressure(); $this->temperature = $subject->getTemperature(); $this->humidity = $subject->getHumidity(); //也可以從推送數據中獲取 $this->pressure = $object["pressure"]; $this->temperature = $object["temperature"]; $this->humidity = $object["humidity"]; } $this->display(); } public function display() { echo "Current pressure: {$this->pressure}, Current temperature: {$this->temperature}"; } }
為什么要加一個 setChanged 方法
setChanged 讓你在更新觀察者時,有更多的彈性,能更適當的通知觀察者,比方說,如果沒有setCanged方法,氣象站溫度變化十分之一度時,都會通知所有觀察者,你肯定不想讓這么頻繁的更新吧.我們可以控制溫度變化達到一度時,調用setChanged,進行有效的更新.
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/26168.html
摘要:這是一個設計模式系列本書所有案例均來自設計模式中文版地址歡迎大家策略模式定義了算法族,分別封裝起來,讓他們之間可以相互調用,此模式讓算法的變化獨立與調用算法的客戶端。 這是一個設計模式系列,本書所有案例均來自「Head-First設計模式(中文版)」, Github地址, 歡迎大家 watch, star 策略模式 定義了算法族,分別封裝起來,讓他們之間可以相互調用,此模式讓算法的變化...
摘要:學習編程的本最佳書籍這些書涵蓋了各個領域,包括核心基礎知識,集合框架,多線程和并發,內部和性能調優,設計模式等。擅長解釋錯誤及錯誤的原因以及如何解決簡而言之,這是學習中并發和多線程的最佳書籍之一。 showImg(https://segmentfault.com/img/remote/1460000018913016); 來源 | 愿碼(ChainDesk.CN)內容編輯 愿碼Slo...
摘要:模塊鏈的共識配置,該配置會寫入創世塊。主要指責是記錄和更新本地累計工作量最高的鏈,并維護鏈上數據的索引。消息使用序列化。協議是節點之間用來處理廣播和轉發新的交易。 by Nervos CKB Team 在 2017 年底,我們感到心里的一些想法,包括分層的網絡以及一個作為共同知識庫(Common Knowledge Base)的區塊鏈,都已經成熟。因此 2018 年元旦一過我們就迫不及...
摘要:年,包括分層的網絡以及一個作為共同知識庫的區塊鏈,都已經成熟。是一個在設計上非常不同的公有鏈協議,也是網絡中的基礎層,是整個加密經濟網絡的信任引擎。主要指責是記錄和更新本地累計工作量最高的鏈,并維護鏈上數據的索引。 說到猿起,這些心里的想法能追溯到 2016 年,甚至更早。2017 年,包括分層的網絡以及一個作為共同知識庫(Common Knowledge Base)的區塊鏈,都已經成...
摘要:觀察者模式定義設計模式中對的定義一個對象稱為維持一系列依賴于它觀察者的對象,將有關狀態的任何變更自動通知給它們。如圖模式比較觀察者模式則多了一個類似于話題調度中心的流程,發布者和訂閱者解耦。 Obeserver(觀察者)模式 定義 《js設計模式》中對Observer的定義:一個對象(稱為subject)維持一系列依賴于它(觀察者)的對象,將有關狀態的任何變更自動通知給它們。 《設計模...
閱讀 1740·2021-11-25 09:43
閱讀 1785·2021-11-24 10:41
閱讀 3105·2021-09-27 13:36
閱讀 811·2019-08-30 15:53
閱讀 3567·2019-08-30 15:44
閱讀 866·2019-08-30 14:03
閱讀 2572·2019-08-29 16:38
閱讀 996·2019-08-29 13:23