該文章屬於《編程中的那些經典套路——設計模式彙總》系列,而且如下內容基於語言PHPphp
今天咱們來談談觀察者模式,這是一個常常用到的設計模式。sql
讓咱們想象一個場景:一個網站有不一樣等級區域的用戶,不一樣等級的的用戶登陸後能夠得到對應的服務(一級用戶登陸後得到一級服務,二級用戶登陸後得到二級服務,…以此類推)。那麼咱們如何寫這段業務邏輯呢?編程
按照通常思路:咱們會寫N個if..else判斷,像下面這樣:segmentfault
//登陸操做..省略 if(一級用戶) { echo ' 一級服務'; } else if(二級用戶){ echo '二級服務'; } else if(三級用戶){ echo '三級服務'; }
但這樣寫代碼有一個弊端,若是咱們又增長了一個等級用戶,那麼咱們是否是要修改原來的代碼呢(增長多一個if..else判斷),這樣作是很是不穩當的,由於寫好的代碼咱們不該該碰它。設計模式
咱們應該寫一段拓展性強與維護性較強的代碼,由此衍生出觀察者模式。數組
觀察者模式的大體思路是這樣的:有一個觀察者列表(A),有一個被觀察者列表(B),當B發生變化時,程序就會遍歷觀察者列表A,隨之執行對應的update操做,而後得到想要的效果。語言表述可能比較難以理解,咱們來看代碼吧。網站
PHP已經幫咱們內置了一個觀察者模式的接口(The SplSubject interface),咱們能夠直接實現這個接口:this
而且php還提供了一個存儲對象的class(即觀察者列表):spa
固然咱們徹底能夠不使用這個類,能夠用數組代替。設計
具體代碼:
觀察者模式.php
<?php //LoginSubject class LoginSubject implements SplSubject{ //觀察者列表 public $observers,$value,$hobby,$address; //初始化變量 public function __construct(){ //sqlObjectStorage是一個類,專門用來存儲內容,觀察者列表就是存在此類 $this->observers = new SplObjectStorage(); } //登陸 public function login(){ //登陸過程,省略 $this->notify(); } //添加觀察者 public function attach(SplObserver $observer){ $this->observers->attach($observer); } //剔除觀察者 public function detach(SplObserver $observer){ $this->observers->detach($observer); } //登錄後通知notify public function notify(){ $observers = $this->observers; //這段rewind不可或缺... 將節點指針指向第一位節點 $observers->rewind(); //當前節點存在 while($observers->valid()){ $observer = $observers->current();//獲取當前節點(即觀察者) $observer->update($this);//進行update犯法操做 $observers->next();//next 節點 } } } //observer User1Observers class User1Observers implements SplObserver { public function update(SplSubject $subject){ echo '我是一級用戶,請給我對應的一級服務'; } } //observer User2Observers class User2Observers implements SplObserver { public function update(SplSubject $subject){ echo '我是二級用戶,請給我對應的二級服務'; } } //observer CommenUserObservers class CommenUserObservers implements SplObserver { public function update(SplSubject $subject){ echo '我是普通用戶,請給我對應的普通服務'; } } //若是須要的話能夠繼續增長或者減小用戶等級,絲絕不會影響本來的等級用戶 $subject = new LoginSubject(); $CommenUserObservers = new CommenUserObservers;//普通用戶 $subject->attach(new User1Observers);//增長觀察者:一級用戶 $subject->attach(new User2Observers);//增長觀察者:二級用戶 $subject->attach($CommenUserObservers);//增長觀察者:普通用戶 $subject->login();//登陸,觸發notify //output:我是一級用戶,請給我對應的一級服務我是二級用戶,請給我對應的二級服務我是普通用戶,請給我對應的普通服務 echo '<br/>'; //若是有一天普通用戶壓根沒有對應的服務了,那麼咱們就能夠剔除它了 //$subject->detach(new CommenUserObservers); 無效 $subject->detach($CommenUserObservers);//刪除觀察者:普通用戶 $subject->login();//登陸,觸發notify,普通用戶就不會被通知啦 //output:我是一級用戶,請給我對應的一級服務我是二級用戶,請給我對應的二級服務 ?>
看出門道了嗎?每當登陸操做的時候,就會順帶觸發notify方法,從而遍歷關注者列表內的對象方法update,從而達到不一樣的用戶得到不一樣的服務目的,而當咱們須要新增/減小用戶等級的時候又不須要修改源代碼,很好的符合了開放封閉原則。
我一直認爲觀察者模式、單例模式、工廠模式三者都是很棒的設計模式,但觀察者模式理解起來稍微比較困難,若是有困惑的話能夠直接在評論區發問。