1. 程式人生 > >必須做作業三:氣象項目中觀察者模式解析

必須做作業三:氣象項目中觀察者模式解析

date edi splay 取數據 app 通知 mov pen con

觀察者模式

定義對象間的一種一對多依賴關系,使得每當一個對象狀態發生改變時,其相關依賴對象皆得到通知並被自動更新。觀察者模式又叫做發布-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。

觀察者模式是一種對象行為型模式。

目的

建立一種對象與對象之間的依賴關系,一個對象發生改變時將自動通知其他對象,其他對象將相應做出反應。在此,發生改變的對象稱為觀察目標,而被通知的對象稱為觀察者,一個觀察目標可以對應多個觀察者,而且這些觀察者之間沒有相互聯系,可以根據需要增加和刪除觀察者,使得系統更易於擴展,這就是觀察者模式的模式動機。

結構

觀察者模式包含如下角色:

Subject: 目標

ConcreteSubject: 具體目標

Observer: 觀察者

ConcreteObserver: 具體觀察者

技術分享圖片

來源

示例

我們以Github上的一個觀察者模式的項目為例,見這裏 。

該項目是一個氣象更新顯示系統,在氣象站數據更新後,能夠自動更新顯示面板的信息。

源碼分析

觀察者觀察的對象

稱為可觀察對象,需要實現具體的註冊和刪除管理者方法。

class AbstractObservable(object):
    def register(self):
        raise NotImplementedError(
            ‘register is a abstract method which must be implemente‘)

    def remove(self):
        raise NotImplementedError(
            ‘remove is a abstract method which must be implemente‘)

觀察者抽象類

讓可觀察對象通知觀察者

class AbstractDisplay(object):
    def update(self):
        raise NotImplementedError(
            ‘update is a abstract method which must be implemente‘)

    def display(self):
        raise NotImplementedError(
            ‘display is a abstract method which must be implemente‘)

Subject

用於管理多個事件的通知,管理多個可觀察對象

class Subject(object):
    def __init__(self, subject):
        self.subject = subject
        self._observers = []

    def register(self, ob):
        self._observers.append(ob)

    def remove(self, ob):
        self._observers.remove(ob)

    def notify(self, data=None):
        for ob in self._observers:
            ob.update(data)

WeatherData

用於管理氣象數據

https://github.com/zhengxiaowai/design-patterns/blob/master/behavioral/observer.py#L41

class WeatherData(AbstractObservable):
    def __init__(self, *namespaces):
        self._nss = {}
        self._clock = None
        self._temperature = None
        self._humidity = None
        self._oxygen = None

        for ns in namespaces:
            self._nss[ns] = Subject(ns)
    ......
    ......

OverviewDisplay

總覽顯示面板,獲取當前數據並顯示

class OverviewDisplay(AbstractDisplay):
    def __init__(self):
        self._data = {}

    def update(self, data):
        self._data = data
        self.display()

    def display(self):
        print(u‘總覽顯示面板:‘)
        for k, v in self._data.items():
            print(k + ‘: ‘ + str(v))

main 函數

借助觀察者模式,氣象數據更新後,可以通過可觀察對象管理者的notify接口,通知觀察者更新數據。

if __name__ == ‘__main__‘:
    import time

    # 生成一個可觀察對象,支持(‘all‘, ‘temperature‘, ‘humidity‘, ‘oxygen‘)的數據通知
    wd = WeatherData(‘all‘, ‘temperature‘, ‘humidity‘, ‘oxygen‘)

    # 兩個觀察者對象
    od = OverviewDisplay()
    td = TemperatureDisplay()

    # 註冊到可觀察對象中,能獲取數據更新
    wd.register(‘all‘, od)
    wd.register(‘temperature‘, td)

    # 更新數據,可觀察對象將會自動更新數據
    wd.set_measurement({
        ‘clock‘: time.strftime("%Y-%m-%d %X", time.localtime()),
        ‘temperature‘: 20,
        ‘humidity‘: 60,
        ‘oxygen‘: 10
    })

    # 一秒後再次更新數據
    time.sleep(1)
    print(‘\n‘)
    wd.set_measurement({
        ‘clock‘: time.strftime("%Y-%m-%d %X", time.localtime()),
        ‘temperature‘: 21,
        ‘humidity‘: 58,
        ‘oxygen‘: 7
    })

優點

當數據更新後,可以自動通知觀察者

目標擴展性更強

實現了目標與觀察者之間的抽象耦合

實現了廣播通信

必須做作業三:氣象項目中觀察者模式解析