1. 程式人生 > >19-Python與設計模式--觀察者模式

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等。


f1.png

 

三、觀察者模式的優點和應用場景

優點:

1、觀察者與被觀察者之間是抽象耦合的;
2、可以將許多符合單一職責原則的模組進行觸發,也可以很方便地實現廣播。

應用場景:

1、訊息交換場景。如上述說到的訊息佇列等;
2、多級觸發場景。比如支援中斷模式的場景中,一箇中斷即會引發一連串反應,就可以使用觀察者模式。

四、觀察者模式的缺點

1、觀察者模式可能會帶來整體系統效率的浪費;
2、如果被觀察者之間有依賴關係,其邏輯關係的梳理需要費些心思。