觀察者模式

觀察者模式

觀察者模式(有時又被稱為模型(Model)-視圖(View)模式、源-收聽者(Listener)模式或從屬者模式)是軟體設計模式的一種。在此種模式中,一個目標物件管理所有相依於它的觀察者物件,並且在它本身的狀態改變時主動發出通知。這通常透過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實現事件處理系統。

基本介紹

  • 中文名:觀察者模式
  • 外文名:Observer
  • 模式軟體設計模式
  • 系統:通常被用來實現事件處理系統
  • 又稱為:發布-訂閱模式
基本介紹,實現方式,觀察,過程,觀察者,被觀察,撤銷觀察,例子,

基本介紹

觀察者模式(Observer)完美的將觀察者和被觀察的對象分離開。舉個例子,用戶界面可以作為一個觀察者,業務數據是被觀察者,用戶界面觀察業務數據的變化,發現數據變化後,就顯示在界面上。面向對象設計的一個原則是:系統中的每個類將重點放在某一個功能上,而不是其他方面。一個對象只做一件事情,並且將他做好。觀察者模式在模組之間劃定了清晰的界限,提高了應用程式的可維護性和重用性。
觀察者設計模式定義了對象間的一種一對多的組合關係,以便一個對象的狀態發生變化時,所有依賴於它的對象都得到通知並自動刷新。

實現方式

觀察者模式有很多實現方式,從根本上說,該模式必須包含兩個角色:觀察者和被觀察對象。在剛才的例子中,業務數據是被觀察對象,用戶界面是觀察者。觀察者和被觀察者之間存在“觀察”的邏輯關聯,當被觀察者發生改變的時候,觀察者就會觀察到這樣的變化,並且做出相應的回響。如果在用戶界面、業務數據之間使用這樣的觀察過程,可以確保界面和數據之間劃清界限,假定應用程式的需求發生變化,需要修改界面的表現,只需要重新構建一個用戶界面,業務數據不需要發生變化。

觀察

實現觀察者模式的時候要注意,觀察者和被觀察對象之間的互動關係不能體現成類之間的直接調用,否則就將使觀察者和被觀察對象之間緊密的耦合起來,從根本上違反面向對象的設計的原則。無論是觀察者“觀察”觀察對象,還是被觀察者將自己的改變“通知”觀察者,都不應該直接調用。

過程

實現觀察者模式有很多形式,比較直觀的一種是使用一種“註冊——通知——撤銷註冊”的形式。下面的三個圖詳細的描述了這樣一種過程:
觀察者模式

觀察者

(Observer)將自己註冊到被觀察對象(Subject)中,被觀察對象將觀察者存放在一個容器(Container)里。

被觀察

被觀察對象發生了某種變化(如圖中的SomeChange),從容器中得到所有註冊過的觀察者,將變化通知觀察者。

撤銷觀察

觀察者告訴被觀察者要撤銷觀察,被觀察者從容器中將觀察者去除。
觀察者將自己註冊到被觀察者的容器中時,被觀察者不應該過問觀察者的具體類型,而是應該使用觀察者的接口。這樣的優點是:假定程式中還有別的觀察者,那么只要這個觀察者也是相同的接口實現即可。一個被觀察者可以對應多個觀察者,當被觀察者發生變化的時候,他可以將訊息一一通知給所有的觀察者。基於接口,而不是具體的實現——這一點為程式提供了更大的靈活性。

例子

Java代碼Demo
//觀察者,需要用到觀察者模式的類需實現此接口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等    }}
php代碼DEMO
<?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();}?>
C++ 觀察者模式例子
//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;}

相關詞條

熱門詞條

聯絡我們