19-Python與設計模式--觀察者模式
一、火警報警器
在門面模式中,我們提到過火警報警器。在當時,我們關注的是通過封裝減少程式碼重複。而今天,我們將從業務流程的實現角度,來再次實現該火警報警器。
class AlarmSensor: def run(self): print "Alarm Ring..." class WaterSprinker: def run(self): print "Spray Water..." class EmergencyDialer: def run(self): print "Dial 119..."
以上是門面模式中的三個感測器類的結構。仔細分析業務,報警器、灑水器、撥號器都是“觀察”煙霧感測器的情況來做反應的。因而,他們三個都是觀察者,而煙霧感測器則是被觀察物件了。根據分析,將三個類提取共性,泛化出“觀察者”類,並構造被觀察者。
觀察者如下:
class Observer: def update(self): pass class AlarmSensor(Observer): def update(self,action): print "Alarm Got: %s" % action self.runAlarm() def runAlarm(self): print "Alarm Ring..." class WaterSprinker(Observer): def update(self,action): print "Sprinker Got: %s" % action self.runSprinker() def runSprinker(self): print "Spray Water..." class EmergencyDialer(Observer): def update(self,action): print "Dialer Got: %s"%action self.runDialer() def runDialer(self): print "Dial 119..."
觀察者中定義了update介面,如果被觀察者狀態比較多,或者每個具體的觀察者方法比較多,可以通過update傳引數進行更豐富的控制。
下面構造被觀察者。
class Observed: observers=[] action="" def addObserver(self,observer): self.observers.append(observer) def notifyAll(self): for obs in self.observers: obs.update(self.action) class smokeSensor(Observed): def setAction(self,action): self.action=action def isFire(self): return True
被觀察者中首先將觀察物件加入到觀察者陣列中,若發生情況,則通過notifyAll通知各觀察者。
業務程式碼如下:
if __name__=="__main__": alarm=AlarmSensor() sprinker=WaterSprinker() dialer=EmergencyDialer() smoke_sensor=smokeSensor() smoke_sensor.addObserver(alarm) smoke_sensor.addObserver(sprinker) smoke_sensor.addObserver(dialer) if smoke_sensor.isFire(): smoke_sensor.setAction("On Fire!") smoke_sensor.notifyAll()
列印如下:
Alarm Got: On Fire!
Alarm Ring...
Sprinker Got: On Fire!
Spray Water...
Dialer Got: On Fire!
Dial 119...
回到目錄
二、觀察者模式
觀察者模式也叫釋出-訂閱模式,其定義如下:定義物件間一種一對多的依賴關係,使得當該物件狀態改變時,所有依賴於它的物件都會得到通知,並被自動更新。
觀察者模式的通知方式可以通過直接呼叫等同步方式實現(如函式呼叫,HTTP介面呼叫等),也可以通過訊息佇列非同步呼叫(同步呼叫指被觀察者釋出訊息後,必須等所有觀察者響應結束後才可以進行接下來的操作;非同步呼叫指被觀察者釋出訊息後,即可進行接下來的操作。)。事實上,許多開源的訊息佇列就直接支援釋出-訂閱模式,如Zero MQ等。
三、觀察者模式的優點和應用場景
優點:
1、觀察者與被觀察者之間是抽象耦合的;
2、可以將許多符合單一職責原則的模組進行觸發,也可以很方便地實現廣播。
應用場景:
1、訊息交換場景。如上述說到的訊息佇列等;
2、多級觸發場景。比如支援中斷模式的場景中,一箇中斷即會引發一連串反應,就可以使用觀察者模式。
四、觀察者模式的缺點
1、觀察者模式可能會帶來整體系統效率的浪費;
2、如果被觀察者之間有依賴關係,其邏輯關係的梳理需要費些心思。