觀察者模式(有時又被稱為模型(Model)-視圖(View)模式、源-收聽者(Listener)模式或從屬者模式)是軟體設計模式的一種。在此種模式中,一個目標物件管理所有相依於它的觀察者物件,並且在它本身的狀態改變時主動發出通知。這通常透過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實現事件處理系統。
基本介紹
- 中文名:觀察者模式
- 外文名:Observer
- 模式:軟體設計模式
- 系統:通常被用來實現事件處理系統
- 又稱為:發布-訂閱模式
基本介紹
實現方式
觀察
過程
觀察者
被觀察
撤銷觀察
例子
//觀察者,需要用到觀察者模式的類需實現此接口public interface Observer{ void update(Object...objs);}//被觀察者(一個抽象類,方便擴展)public abstract class Observable{ public final ArrayList<Class<?>> obserList = new ArrayList<Class<?>>(); /**AttachObserver(通過實例註冊觀察者) *<b>Notice:</b>obcan'tbenull,oritwillthrowNullPointerException **/ public<T> void registerObserver(T ob){ if(ob==null) throw new NullPointerException(); this.registerObserver(ob.getClass()); } /** *AttachObserver(通過Class註冊觀察者) *@paramcls */ public void registerObserver(Class<?> cls){ if(cls==null) throw new NullPointerException(); synchronized(obserList){ if(!obserList.contains(cls)){ obserList.add(cls); } } } /**UnattachObserver(註銷觀察者) *<b>Notice:</b> *<b>ItreverseswithattachObserver()method</b> **/ public<T>void unRegisterObserver(Tob){ if(ob==null) throw new NullPointerException(); this.unRegisterObserver(ob.getClass()); } /**UnattachObserver(註銷觀察者,有時候在未獲取到實例使用) *<b>Notice:</b> *<b>ItreverseswithattachObserver()method</b> **/ public void unRegisterObserver(Class<?>cls){ if(cls==null) throw new NullPointerException(); synchronized(obserList){ Iterator<Class<?>>iterator=obserList.iterator(); while(iterator.hasNext()){ if(iterator.next().getName().equals(cls.getName())){ iterator.remove(); break; } } } } /**detachallobservers*/ public void unRegisterAll(){ synchronized(obserList){ obserList.clear(); } } /**Ruturnthesizeofobservers*/ public int countObservers(){ synchronized(obserList){ return obserList.size(); } } /** *notify all observer(通知所有觀察者,在子類中實現) *@paramobjs */ public abstract void notifyObservers(Object... objs); /** *notify one certain observer(通知某一個確定的觀察者) *@paramcls *@paramobjs */ public abstract void notifyObserver(Class<?> cls, Object... objs); /** *notifyonecertainobserver *@paramcls *@paramobjs */ public abstract<T> void notifyObserver(T t, Object... objs);}//目標被觀察者public class ConcreteObservable extends Observable{ private static ConcreteObservableinstance = null; private ConcreteObservable(){}; public static synchronized ConcreteObservablegetInstance(){ if(instance == null){ instance=newConcreteObservable(); } returninstance; } @Override public <T> void notifyObserver(T t, Object... objs){ if(t == null) throw new NullPointerException(); this.notifyObserver(t.getClass(), objs); } @Override public void notifyObservers(Object... objs){ for(Class<?>cls : obserList){ this.notifyObserver(cls, objs); } } //通過java反射機制實現調用 @Override public void notifyObserver(Class<?>cls, Object...objs){ if(cls == null) throw new NullPointerException(); Method[] methods = cls.getDeclaredMethods(); for(Method method : methods){ if(method.getName().equals("update")){ try{ method.invoke(cls,objs); break; }catch(IllegalArgumentException e){ e.printStackTrace(); }catch(IllegalAccessException e){ e.printStackTrace(); }catch(InvocationTargetException e){ e.printStackTrace(); } } } }}//使用(實現Observer接口)public class Text extends Activity implements Observer{ publicvoidonCreate(...){ ConcreteObservable.getInstance().registerObserver(Text.class); .... } //實現接口處理 publicvoidupdate(Object...objs){ //做操作,比如更新數據,更新UI等 }}
<?phpclass car implements SplSubject{ //車的類型 private $carName; //車的狀態,0為關閉,1這啟動車子 private $carState = 0; //初始化車的速度表值 private $carSpeed = 0; //各項車的性能觀察對象 private $Observers; public function __construct($Name) { $this->carName = $Name; $this->Observers = new SplObjectStorage; } //啟動 public function start() { $this->carState = 1; $this->notify(); } //停車 public function stop() { $this->carState = 0; $this->carSpeed = 0; $this->notify(); } //加速 public function accelerate($Acceleration) { if (0 === $this->carState) { throw new Exception('先踩油門,不然車怎走啊!!!'); } if (!is_int($Acceleration) || $Acceleration < 0) { throw new Exception('加速值錯了啊'); } $this->carSpeed += $Acceleration; $this->notify(); } //增加監測對象 public function attach(SplObserver $observer) { if (!$this->Observers->contains($observer)) { $this->Observers->attach($observer); } return true; } //刪除監測對象 public function detach(SplObserver $observer) { if (!$this->Observers->contains($observer)) { return false; } $this->Observers->detach($observer); return true; } //傳送對象 public function notify() { foreach ($this->Observers as $observer) { $observer->update($this); } } public function __get($Prop) { switch ($Prop) { case 'STATE': return $this->carState; break; case 'SPEED': return $this->carSpeed; break; case 'NAME': return $this->carName; break; default: throw new Exception($Prop . 'cannotberead'); } } public function __set($Prop, $Val) { throw new Exception($Prop . 'cannotbeset'); }}class carStateObserver implements SplObserver{ private $SubjectState; public function update(SplSubject $subject) { switch ($subject->STATE) { case 0: if (is_null($this->SubjectState)) { echo $subject->NAME . '沒有啟動呢' . "\t"; } else { echo $subject->NAME . '熄火了' . "\t"; } $this->SubjectState = 0; break; case 1: if (1 !== $this->SubjectState) { echo $subject->NAME . '啟動了' . "\t"; $this->SubjectState = 1; } break; default: throw new Exception('UnexpectederrorincarStateObserver::update()'); } }}class carSpeedObserver implements SplObserver{ public function update(SplSubject $subject) { if (0 !== $subject->STATE) { echo $subject->NAME . '目前速度為' . $subject->SPEED . 'Kmh' . "\t"; } }}class carOverspeedObserver implements SplObserver{ public function update(SplSubject $subject) { if ($subject->SPEED > 130) { throw new Exception('加速限制在130以內,你違規了!' . "\t"); } }}try { $driver = new car('AUDIA4'); $driverObserver1 = new carStateObserver; $driverObserver2 = new carSpeedObserver; $drivesrObserver3 = new carOverspeedObserver; $driver->attach($driverObserver1); $driver->attach($driverObserver2); $driver->attach($drivesrObserver3); $driver->start(); $driver->accelerate(10); $driver->accelerate(30); $driver->stop(); $driver->start(); $driver->accelerate(50); $driver->accelerate(70); $driver->accelerate(100); $driver->accelerate(150);}catch (Exception $e) { echo $e->getMessage();}?>
//filename observer.h#include <iostream>#include <set>#include <string>using namespace std;/////////////////////抽象模式定義class CObservable;//觀察者,純虛基類class CObserver{public: CObserver(){}; virtual ~CObserver(){}; //當被觀察的目標發生變化時,通知調用該方法 //來自被觀察者pObs, 擴展參數為pArg virtual void Update(CObservable* pObs, void* pArg = NULL) = 0;};//被觀察者,即Subjectclass CObservable{public: CObservable() : m_bChanged(false) {}; virtual ~CObservable() {}; void Attach(CObserver* pObs); //註冊觀察者 void Detach(CObserver* pObs); //註銷觀察者 void DetachAll(); //註銷所有觀察者 void Notify(void* pArg = NULL); //若狀態變化,則遍歷觀察者,逐個通知更新 bool HasChanged(); //測試目標狀態是否變化 int GetObserversCount(); //獲取觀察者數量protected: void SetChanged(); //設定狀態變化!!!必須繼承CObservable才能設定目標狀態 void ClearChanged(); //初始化目標為未變化狀態private: bool m_bChanged; //狀態 set<CObserver*> m_setObs; //set保證目標唯一性};/////////////////////抽象模式實現void CObservable::Attach(CObserver* pObs){ if (!pObs) return; m_setObs.insert(pObs);}void CObservable::Detach(CObserver* pObs){ if (!pObs) return; m_setObs.erase(pObs);}void CObservable::DetachAll(){ m_setObs.clear();}void CObservable::SetChanged(){ m_bChanged = true;}void CObservable::ClearChanged(){ m_bChanged = false;}bool CObservable::HasChanged(){ return m_bChanged;}int CObservable::GetObserversCount(){ return m_setObs.size();}void CObservable::Notify(void* pArg /* = NULL */){ if (!HasChanged()) return; cout << "notify observers…" << endl; ClearChanged(); set<CObserver*>::iterator itr = m_setObs.begin(); for (; itr != m_setObs.end(); itr++){ (*itr)->Update(this, pArg); }}/////////////////////具體套用類定義和實現//bloger是發布者,即被觀察者(subject)class CBloger : public CObservable{public: void Publish(const string &strContent){ cout << "bloger publish, content: " << strContent << endl; SetChanged(); Notify(const_cast<char*>(strContent.c_str())); }};//portal是發布者,即被觀察者(subject)class CPortal : public CObservable{public: void Publish(const string &strContent){ cout << "portal publish, content: " << strContent << endl; SetChanged(); Notify(const_cast<char*>(strContent.c_str())); }};//RSS閱讀器,觀察者class CRSSReader : public CObserver{public: CRSSReader(const string &strName) : m_strName(strName){} virtual void Update(CObservable* pObs, void* pArg = NULL){ char* pContent = static_cast<char*>(pArg); //觀察多個目標 if (dynamic_cast<CBloger*>(pObs)){ cout << m_strName << " updated from bloger, content: " << pContent << endl; }else if (dynamic_cast<CPortal*>(pObs)){ cout << m_strName << " updated from portal, content: " << pContent << endl; } }private: string m_strName;};//Mail閱讀器,觀察者class CMailReader : public CObserver{public: CMailReader(const string &strName) : m_strName(strName){} virtual void Update(CObservable* pObs, void* pArg = NULL){ char* pContent = static_cast<char*>(pArg); if (dynamic_cast<CBloger*>(pObs)){ cout << m_strName << " updated from bloger, content: " << pContent << endl; } if (dynamic_cast<CPortal*>(pObs)){ cout << m_strName << " updated from portal, content: " << pContent << endl; } }private: string m_strName;};#include "observer.h"int main(){ //目標(被觀察者) CBloger* pBloger = new CBloger(); CPortal* pPortal = new CPortal(); //觀察者. 一個觀察者可以觀察多個目標 CRSSReader* pRssReader = new CRSSReader("rss reader"); CMailReader* pMailReader = new CMailReader("mail reader"); pBloger->Attach(pRssReader); //bloger註冊觀察者 pBloger->Attach(pMailReader); //bloger註冊觀察者 pPortal->Attach(pRssReader); //portal註冊觀察者 pPortal->Attach(pMailReader); //portal註冊觀察者 //部落格發布信息 pBloger->Publish("部落格分享設計模式"); cout << endl; //門戶發布信息 pPortal->Publish("門戶分享設計模式"); cout << "\nportal detached mail reader" << endl; pPortal->Detach(pMailReader); cout << "portal observers count: " << pPortal->GetObserversCount() << endl << endl; pPortal->Publish("門戶分享設計模式"); system("pause"); return 0;}