觀察者模式,無需多執行緒完成資料監聽

TechFlow2019發表於2021-01-15

大家好,我們今天來了解一個新的設計模式——觀察者模式

觀察者模式的思路很簡單,它被廣泛地用在各種資料監控上。很多時候我們希望監聽某個資料的變化,希望一旦獲悉它的變化之後立即採取一些舉措。按照常規的操作,我們需要開啟額外的執行緒來進行監聽。但是開啟執行緒一則非常麻煩,二則需要帶來額外的開銷,我們今天介紹的觀察者模式就可以在無需多餘開銷的基礎上完成這個功能

觀察者

在觀察者模式當中,整個執行流和常規的操作相反,我們並不是用一些程式去監聽資料的變化。相反而是當資料發生變化的時候,我們去通知對應的監聽器資料產生了變化。好處我們前面也說過了,可以避免多餘的開銷。

首先,我們來實現兩個監聽器。也就是當資料發生變化之後會觸發這兩個監聽器。在這個設計模式當中,監聽器被命名為viewer,這裡的觀察不是一種主動的觀察而是一種被動地接收通知。也許是起名的人想不出更好的名字來吧,其實我覺得應該叫做receiver更好。

class IncreaseViewer:

    def __init__(self):
        self.data = 0

    def update(self, subject):
        # 判斷是否增加
        if subject.data > self.data:
            print('Increased: Subject {} data increased to {}'.format(subject.name, subject.data))
            self.data = subject.data


class DeclineViewer:

    def __init__(self):
        self.data = 0

    def update(self, subject):
        # 判斷是否減少
        if subject.data < self.data:
        print('Decreased: Subject %s data decreased to %d' % (subject.name, subject.data))
        self.data = subject.data

資料

觀察者的程式碼應該很好理解,理解了觀察者類之後,我們再來看看資料類。

資料的類其實也很簡單,我們只需要設計一個功能,讓它可以在資料發生賦值操作的時候去通知一下觀察者就可以了。我們都知道在Python當中,賦值操作是沒辦法直接感知的,但是類當中的成員發生變化的時候,我們是可以通過@property裝飾器來進行修飾的。

所以我們就利用這一點來實現資料這個類,如果大家熟悉@property註解的話,也非常簡單。

class Data(Subject):

    def __init__(self, name=''):
        Subject.__init__(self)
        self.name = name
        self._data = 0

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, data):
        self._data = data
        # 關鍵
        self.notify()

大家看到了data這個方法當中的self.notify了嗎?這個就是通知函式,所以就是當Data這個類當中的data成員發生變化的時候,我們執行通知操作,去通知觀察者執行。

管理觀察者

現在我們觀察者實現好了,資料類也有了,剩下的就是把這兩者連通起來了。我們當然也可以簡單粗暴地用程式碼實現,但是比較好的做法是對資料和觀察者之間的聯絡做一個簡單的管理。因為可能不同的資料需要的觀察者不一樣,我們並不能簡單粗暴地一概而論。

其實管理觀察者也不需要太複雜,只需要用物件導向的思路對list進行一個簡單的封裝即可。

class Subject:

    def __init__(self):
        self._observer = []

    def attach(self, observer):
        if observer not in self._observer:
            self._observer.append(observer)

    def detach(self, observer):
        try:
            self._observer.remove(observer)
        except ValueError:
            pass

    def notify(self, modifier=None):
        for observer in self._observer:
            if modifier != observer:
                observer.update(self)

attach表示關聯,也就是給資料關聯上觀察者,detach表示解除關聯,notify自然就是通知了。其實也就是用一個迴圈遍歷一下所有的觀察者,然後執行一下對應的update函式就可以了。

這裡為了簡化邏輯,我們把Subject類做成了Data類的父類。這樣某種程度上相當於解耦了觀察者和資料,我們以後無論是對哪部分邏輯進行修改或者是優化都不會影響另外兩方。整個程式碼不過50行,可以說是非常簡便了,不僅是Python,對於其他支出多型的語言來說,這個設計模式也是同樣適用的。

到這裡關於觀察者模式就介紹完了,今天的文章就到這裡。衷心祝願大家每天都有所收穫。如果還喜歡今天的內容的話,請來一個三連支援吧~(點贊、關注、轉發

相關文章