词条 | 观察者模式 |
释义 | 观察者<Observer>模式(有时又被称为发布-订阅<Publish/Subscribe>模式、模型-视图<Model/View>模式、源-收听者<Source/Listener>模式或从属者<Dependents>模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。 基本简介观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。 实现方式观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者和被观察对象。在刚才的例子中,业务数据是被观察对象,用户界面是观察者。观察者和被观察者之间存在“观察”的逻辑关联,当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应。如果在用户界面、业务数据之间使用这样的观察过程,可以确保界面和数据之间划清界限,假定应用程序的需求发生变化,需要修改界面的表现,只需要重新构建一个用户界面,业务数据不需要发生变化。 “观察”不是“直接调用”实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。 实现观察者模式的过程实现观察者模式有很多形式,比较直观的一种是使用一种“注册——通知——撤销注册”的形式。下面的三个图详细的描述了这样一种过程: 1、观察者(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。 2、被观察对象被观察对象发生了某种变化(如图中的SomeChange),从容器中得到所有注册过的观察者,将变化通知观察者。 3、撤销观察观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。 观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现——这一点为程序提供了更大的灵活性。 实现观察者模式的例子php代码DEMO: <?php class 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.' cannot be read'); } } public function __set ($Prop, $Val) { throw new Exception ($Prop.' cannot be set'); } } 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\\r\"; } else { echo $subject -> NAME.' 熄火了'."\\t\\r\"; } $this -> SubjectState = 0; break; case 1: if (1 !== $this -> SubjectState) { echo $subject -> NAME.' 启动了'."\\t\\r\"; $this -> SubjectState = 1; } break; default : throw new Exception ('Unexpected error in carStateObserver::update()'); } } } class carSpeedObserver implements SplObserver { public function update(SplSubject $subject) { if (0 !== $subject -> STATE) { echo $subject -> NAME.' 目前速度为 '.$subject -> SPEED.'Kmh '."\\t\\r\"; } } } class carOverspeedObserver implements SplObserver { public function update(SplSubject $subject) { if ($subject -> SPEED > 130) { throw new Exception ('加速限制在130以内, 你违规了!'."\\t\\r\"); } } } try { $driver = new car ('AUDI A4'); $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++ 观察者模式例子 #include <iostream> #include <set> #include <string> using namespace std; /////////////////////抽象模式定义 class CObservable; //观察者,纯虚基类 class CObserver { public: CObserver::CObserver(){}; virtual CObserver::~CObserver(){}; //当被观察的目标发生变化时,通知调用该方法 //来自被观察者pObs, 扩展参数为pArg virtual void Update(CObservable* pObs, void* pArg = NULL) = 0; }; //被观察者,即Subject class 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: //设置状态变化!!!必须继承CObservable才能设置目标状态 void SetChanged(); //初始化目标为未变化状态 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; }; /////////////////Main 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 << "\portal detached mail reader" << endl; pPortal->Detach(pMailReader); cout << "portal observers count: " << pPortal->GetObserversCount() << endl << endl; pPortal->Publish("门户分享设计模式"); system("pause"); return 0; } |
随便看 |
百科全书收录4421916条中文百科知识,基本涵盖了大多数领域的百科知识,是一部内容开放、自由的电子版百科全书。