一、火警報警器
在門面模式中,我們提到過火警報警器。在當時,我們關注的是通過封裝減少代碼重複。而今天,我們將從業務流程的實現角度,來再次實現該火警報警器。
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、如果被觀察者之間有依賴關係,其邏輯關係的梳理需要費些心思。