国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

python設(shè)計(jì)模式-觀察者模式

terasum / 823人閱讀

摘要:在程序設(shè)計(jì)中,觀察者模式通常被定義為觀察者模式定義了對(duì)象之間的一對(duì)多依賴,這樣一來(lái),當(dāng)一個(gè)對(duì)象改變狀態(tài)是,它的所有依賴者都會(huì)收到通知并自動(dòng)更新。事件扮演發(fā)布者的角色,監(jiān)聽(tīng)者則扮演觀察者的角色。

題目:現(xiàn)在你有一個(gè)數(shù)字,默認(rèn)格式化程序是以十進(jìn)制格式展示此數(shù)值,但需要提供一個(gè)功能,這個(gè)程序要支持添加/注冊(cè)更多的格式化程序(比如:添加一個(gè)十六進(jìn)制格式化程序和一個(gè)二進(jìn)制格式化程序)。每次數(shù)值更新時(shí),已注冊(cè)的程序就會(huì)收到通知,并顯示更新后的值。

我們看下需求:

NumberFormatter 有一個(gè) number 屬性

當(dāng) number 值修改時(shí),相關(guān)的格式化方式展示結(jié)果要改變

此系統(tǒng)必須可擴(kuò)展已適應(yīng)其他格式化方式的使用。

一個(gè)錯(cuò)誤的實(shí)現(xiàn)可能是這樣的:

class NumberFormatter(object):
    def __init__(self, number):
        self.number = number
        
    def show_data(self):
        self.default_formatter()
        self.hex_formatter()
        self.binary_formatter()
        
    def default_formatter(self):
        pass
        
    def hex_formatter(self):
        pass
        
    def binary_formatter(self):
        pass

我們可以這么使用:

number = NumberFormatter(10)
number.show_data()

但是這樣會(huì)有一個(gè)問(wèn)題:這種針對(duì)實(shí)現(xiàn)的編程會(huì)導(dǎo)致我們?cè)谠黾踊蛘邉h除需要格式化方式時(shí)必須修改代碼。比如我們現(xiàn)在不再需要十六進(jìn)制數(shù)字格式的顯示,就需要把 hex_formatter 相關(guān)的代碼刪除或者注釋掉。

要解決這個(gè)問(wèn)題,就可以用到我們這次要介紹的觀察者模式了。

什么是觀察者模式 認(rèn)識(shí)觀察者模式

我們先看看報(bào)紙和雜志的訂閱是怎么回事:

報(bào)社的業(yè)務(wù)就是出版報(bào)紙

向某家報(bào)社訂閱報(bào)紙,只要他們有新報(bào)紙,就會(huì)給你送來(lái),只要你是他們的訂戶,你就會(huì)一直受到新報(bào)紙。

當(dāng)你不再想看的時(shí)候,取消訂閱,他們就不會(huì)在送新報(bào)紙給你

只要報(bào)社還在運(yùn)營(yíng),就會(huì)一直有人向他們訂閱報(bào)紙或取消訂閱。

我們用圖表示一下,這里出版者 改稱為主題(Subject)訂閱者改稱為觀察者(Observer)

1. 開(kāi)始的時(shí)候,鴨子對(duì)象不是觀察者

2. 鴨子對(duì)象過(guò)來(lái)告訴主題,它想當(dāng)一個(gè)觀察者(鴨子其實(shí)想說(shuō)的是:我對(duì)你的數(shù)據(jù)改變感興趣,一有變化請(qǐng)通知我)

3. 鴨子對(duì)象已經(jīng)是觀察者了(鴨子靜候通知,一旦接到通知,就會(huì)得到一個(gè)整數(shù))。

4. 主題有了新的數(shù)據(jù)(現(xiàn)在鴨子和其他所有觀察者都會(huì)受到通知:主題已經(jīng)改變

5. 老鼠對(duì)象要求從觀察者中把自己除名(老鼠已經(jīng)觀察次主題太久,決定不再當(dāng)觀察者了)。

6. 老鼠離開(kāi)了(主題知道老鼠的請(qǐng)求后,把它從觀察者中移除了)。

7. 主題有了一個(gè)新的整數(shù)(除了老鼠之外,每個(gè)觀察者都會(huì)收到通知,如果老鼠又想當(dāng)觀察者了,它還可以再回來(lái))

定義觀察者模式

當(dāng)你試圖勾勒觀察者模式時(shí),可以利用報(bào)紙訂閱服務(wù),以及出版這和訂閱者比你這一切。在程序設(shè)計(jì)中,觀察者模式通常被定義為:

觀察者模式定義了對(duì)象之間的一對(duì)多依賴,這樣一來(lái),當(dāng)一個(gè)對(duì)象改變狀態(tài)是,它的所有依賴者都會(huì)收到通知并自動(dòng)更新。

我們和之前的例子做個(gè)對(duì)比:

主題和觀察者定義了一對(duì)多的關(guān)系。觀察者依賴于此主題,只要主題狀態(tài)一有變化,觀察者就會(huì)被通知。根據(jù)通知的風(fēng)格,觀察者可能因此新值而更新。

現(xiàn)在你可能有疑問(wèn),這和一對(duì)多的關(guān)系有何關(guān)聯(lián)?

利用觀察者模式,主題是具有狀態(tài)的對(duì)象,并且可以控制這些狀態(tài)。也就是說(shuō),有一個(gè)具有狀態(tài)的主題。另一方面,觀察者使用這些狀態(tài),雖然這些狀態(tài)不屬于他們。有許多觀察者,依賴主題告訴他們狀態(tài)何時(shí)改變了。這就產(chǎn)生了一個(gè)關(guān)系:一個(gè)主題對(duì)多個(gè)觀察者的關(guān)系

觀察者和主題之間的依賴關(guān)系是如何產(chǎn)生的?

主題是真正擁有數(shù)據(jù)的人,觀察者是主題的依賴者,在數(shù)據(jù)變化時(shí)更新,這樣比起讓許多對(duì)象控制同一份數(shù)據(jù)來(lái),可以得到更干凈的 OO 設(shè)計(jì)。
觀察者模式的應(yīng)用案例

觀察者模式在實(shí)際應(yīng)用中有許多的案例,比如信息的聚合。無(wú)論格式為 RSS、Atom 還是其它,思想多事一樣的:你追隨某個(gè)信息源,當(dāng)它每次更新時(shí),你都會(huì)收到關(guān)于更新的通知。
事件驅(qū)動(dòng)系統(tǒng)是一個(gè)可以使用觀察者模式的例子。在這種系統(tǒng)中,監(jiān)聽(tīng)者被用于監(jiān)聽(tīng)特定的事件。監(jiān)聽(tīng)者的事件被創(chuàng)建出來(lái)時(shí)就會(huì)觸發(fā)它們。這個(gè)事件可以使鍵入某個(gè)特定的鍵、移動(dòng)鼠標(biāo)或者其他。事件扮演發(fā)布者的角色,監(jiān)聽(tīng)者則扮演觀察者的角色。

Python 實(shí)現(xiàn)

現(xiàn)在,讓我們回到文章開(kāi)始的那個(gè)問(wèn)題。

這里我們可以實(shí)現(xiàn)一個(gè)基類 Publisher,包括添加、刪除及通知觀察者這些公用功能。DefaultFormatter 類繼承自 Publisher,并添加格式化程序特定的功能。

Publisher 的代碼如下:

import itertools

"""
觀察者模式實(shí)現(xiàn)
"""

class Publisher:

    def __init__(self):
        self.observers = set()

    def add(self, observer, *observers):
        for observer in itertools.chain((observer, ), observers):
            self.observers.add(observer)
            observer.update(self)

    def remove(self, observer):
        try:
            self.observers.discard(observer)
        except ValueError:
            print("Failed to remove: {}".format(observer))

    def notify(self):
        [observer.update(self) for observer in self.observers]

現(xiàn)在,打算使用觀察者模式的模型或類都應(yīng)該繼承 Publisher 類。該類用 set 來(lái)保存觀察者對(duì)象。當(dāng)用戶向 Publisher 注冊(cè)新的觀察者對(duì)象時(shí),觀察者的 update() 方法會(huì)執(zhí)行,這使得它能夠用模型當(dāng)前的狀態(tài)初始化自己。模型狀態(tài)發(fā)生變化時(shí),應(yīng)該調(diào)用繼承而來(lái)的 notify() 方法,這樣的話,就會(huì)執(zhí)行每個(gè)觀察者對(duì)象的 update() 方法,以確保他們都能反映出模型的最新?tīng)顟B(tài)。

add() 方法的寫(xiě)法值得注意,這里是為了支持可以接受一個(gè)或多個(gè)觀察者對(duì)象。這里我們采用了itertools.chain() 方法,它可以接受任意數(shù)量的  iterable,并返回單個(gè)iterable。遍歷這個(gè) iterable,也就相當(dāng)于依次遍歷參數(shù)里的那些 iterable。

接下來(lái)是 DefaultFomatter 類。__init__() 做的第一件事就是調(diào)用基類的__init__() 方法,因?yàn)檫@在 Python 中沒(méi)法自動(dòng)完成。DefaultFormatter 實(shí)例有自己的名字,這樣便于我們跟蹤其狀態(tài)。對(duì)于_data 變量,我們使用了名稱改編來(lái)聲明不能直接訪問(wèn)該變量。DefaultFormatter_data 變量用作一個(gè)整數(shù),默認(rèn)值為0。

class DefaultFormatter(Publisher):

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

    def __str__(self):
        return "{}: "{}" has data = {}".format(type(self).__name__, self.name, self._data)

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

    @data.setter
    def data(self, new_value):
        try:
            self._data = int(new_value)
        except ValueError as e:
            print("Error: {}".format(e))
        else:
            self.notify()

__str__() 方法返回關(guān)于發(fā)布者名稱和 _data 值的信息。type(self).__name 是一種獲取類名的方便技巧,避免硬編碼類名。(不過(guò)這會(huì)降低代碼的可讀性)

data() 方法有兩個(gè),第一個(gè)使用了 @property 裝飾器來(lái)提供_data 變量的讀訪問(wèn)方式。這樣,我們就能使用 object.data 來(lái)代替 object._data。第二個(gè) data() 方法使用了@setter 裝飾器,改裝飾器會(huì)在每次使用賦值操作符(=)為_data 變量賦值時(shí)被調(diào)用。該方法也會(huì)嘗試把新值強(qiáng)制轉(zhuǎn)換為一個(gè)整數(shù),并在轉(zhuǎn)換失敗時(shí)處理異常。

接下來(lái)是添加觀察者。HexFormatterBinaryFormatter 功能基本相似。唯一的不同在于如何格式化從發(fā)布者那獲取到的數(shù)據(jù)值,即十六進(jìn)制和二進(jìn)制格式化。

class HexFormatter:

    def update(self, publisher):
        print("{}: "{}" has now hex data= {}".format(type(self).__name__,
                                                     publisher.name, hex(publisher.data)))

class BinaryFormatter:

    def update(self, publisher):
        print("{}: "{}" has now bin data= {}".format(type(self).__name__,
                                                     publisher.name, bin(publisher.data)))

接下來(lái)我們添加一下測(cè)試數(shù)據(jù),運(yùn)行代碼觀察一下結(jié)果:

def main():
    df = DefaultFormatter("test1")
    print(df)

    print()
    hf = HexFormatter()
    df.add(hf)
    df.data = 3
    print(df)

    print()
    bf = BinaryFormatter()
    df.add(bf)
    df.data = 21
    print(df)

    print()
    df.remove(hf)
    df.data = 40
    print(df)

    print()
    df.remove(hf)
    df.add(bf)

    df.data = "hello"
    print(df)

    print()
    df.data = 4.2
    print(df)


if __name__ == "__main__":
    main()

完整代碼參考:https://gist.github.com/gusibi/93a000c79f3d943dd58dcd39c4b547f1

運(yùn)行代碼:

python observer.py    
## output
DefaultFormatter: "test1" has data = 0

HexFormatter: "test1" has now hex data= 0x0
HexFormatter: "test1" has now hex data= 0x3
DefaultFormatter: "test1" has data = 3

BinaryFormatter: "test1" has now bin data= 0b11
BinaryFormatter: "test1" has now bin data= 0b10101
HexFormatter: "test1" has now hex data= 0x15
DefaultFormatter: "test1" has data = 21

BinaryFormatter: "test1" has now bin data= 0b101000
DefaultFormatter: "test1" has data = 40

BinaryFormatter: "test1" has now bin data= 0b101000
Error: invalid literal for int() with base 10: "hello"
DefaultFormatter: "test1" has data = 40

BinaryFormatter: "test1" has now bin data= 0b100
DefaultFormatter: "test1" has data = 4

在輸出中我們看到,添加額外的觀察者,就會(huì)出現(xiàn)更多的輸出;一個(gè)觀察者被刪除后就不再被通知到。

總結(jié)

這一篇我們介紹了觀察者模式的原理以及 Python 代碼的實(shí)現(xiàn)。在實(shí)際的項(xiàng)目開(kāi)發(fā)中,觀察者模式廣泛的運(yùn)用于 GUI 編程,而且在仿真及服務(wù)器等其他時(shí)間處理架構(gòu)中也能用到,比如:數(shù)據(jù)庫(kù)觸發(fā)器Django 的信號(hào)系統(tǒng)Qt GUI 應(yīng)用程序框架的信號(hào)(signal)與槽(slot)機(jī)智以及WebSocket的許多用例。

參考鏈接

The 10 Minute Guide to the Observer Pattern in Python

Observer


最后,感謝女朋友支持。

歡迎關(guān)注(April_Louisa) 請(qǐng)我喝芬達(dá)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/40864.html

相關(guān)文章

  • Python設(shè)計(jì)模式之監(jiān)聽(tīng)者模式

    摘要:監(jiān)聽(tīng)模式又名觀察者模式發(fā)布訂閱模式源監(jiān)聽(tīng)器模式,模式的核心是設(shè)計(jì)時(shí)要區(qū)分誰(shuí)是被觀察者,誰(shuí)是觀察者。 監(jiān)聽(tīng)模式 又名觀察者模式、發(fā)布/訂閱模式、源-監(jiān)聽(tīng)器(Source/Listener)模式,模式的核心是:設(shè)計(jì)時(shí)要區(qū)分誰(shuí)是被觀察者,誰(shuí)是觀察者。被觀察者至少有三個(gè)方法,添加觀察者、刪除觀察者、監(jiān)聽(tīng)目標(biāo)變化并通知觀察者;觀察者這至少包含一個(gè)方法,當(dāng)接收到被觀察者的通知時(shí),做出相應(yīng)的處理(即...

    hlcfan 評(píng)論0 收藏0
  • 設(shè)計(jì)模式(python實(shí)現(xiàn)):察者模式

    摘要:所以,以后,只有甲乙會(huì)收到消息。原理當(dāng)我們遇到一個(gè)多對(duì)一的依賴關(guān)系時(shí),就可以用觀察者模式。觀察者模式有一個(gè)被觀察者和多個(gè)觀察者。被觀察者提供注冊(cè)刪除通知的功能,觀察者提供數(shù)據(jù)更新和展示等功能。 1.白話栗子 市里新修了一個(gè)圖書(shū)館,現(xiàn)在招募一個(gè)圖書(shū)管理員叫T,T知道圖書(shū)館里的圖書(shū)更新和借閱等信息。現(xiàn)在有三個(gè)同學(xué)甲乙丙想去了解以后幾個(gè)月的圖書(shū)館圖書(shū)信息和借閱信息,于是它們?nèi)那里注冊(cè)登記。...

    idealcn 評(píng)論0 收藏0
  • python設(shè)計(jì)模式

    摘要:在本節(jié)實(shí)驗(yàn)中,我們學(xué)習(xí)了四種設(shè)計(jì)模式策略模式,觀察者模式,命令模式以及模板方法模式。這四種設(shè)計(jì)模式都是行為型模式。這就是適配器模式。下面讓我們看看適配器模式在實(shí)驗(yàn)樓中使用吧。準(zhǔn)確來(lái)說(shuō),裝飾者模式能動(dòng)態(tài)的給對(duì)象添加行為。 1、策略模式 策略模式將各種操作(算法)進(jìn)行封裝,并使它們之間可以互換。互換的意思是說(shuō)可以動(dòng)態(tài)改變對(duì)象的操作方式(算法)。 -- coding: utf-8 -- im...

    array_huang 評(píng)論0 收藏0
  • 每天一個(gè)設(shè)計(jì)模式之訂閱-發(fā)布模式

    摘要:借助繼承為對(duì)象安裝發(fā)布訂閱功能根據(jù)自己需求定義一個(gè)函數(shù)供事件處理完后調(diào)用創(chuàng)建個(gè)回調(diào)函數(shù)訂閱和這個(gè)事件,并且綁定相關(guān)的完成后的函數(shù)當(dāng)兩個(gè)事件完成時(shí)候,觸發(fā)前幾行綁定的相關(guān)函數(shù)打印實(shí)現(xiàn)中一般用事件模型來(lái)代替?zhèn)鹘y(tǒng)的發(fā)布訂閱模式。 博主按:《每天一個(gè)設(shè)計(jì)模式》旨在初步領(lǐng)會(huì)設(shè)計(jì)模式的精髓,目前采用javascript(_靠這吃飯_)和python(_純粹喜歡_)兩種語(yǔ)言實(shí)現(xiàn)。誠(chéng)然,每種設(shè)計(jì)模式都...

    printempw 評(píng)論0 收藏0
  • 每天一個(gè)設(shè)計(jì)模式之訂閱-發(fā)布模式

    摘要:借助繼承為對(duì)象安裝發(fā)布訂閱功能根據(jù)自己需求定義一個(gè)函數(shù)供事件處理完后調(diào)用創(chuàng)建個(gè)回調(diào)函數(shù)訂閱和這個(gè)事件,并且綁定相關(guān)的完成后的函數(shù)當(dāng)兩個(gè)事件完成時(shí)候,觸發(fā)前幾行綁定的相關(guān)函數(shù)打印實(shí)現(xiàn)中一般用事件模型來(lái)代替?zhèn)鹘y(tǒng)的發(fā)布訂閱模式。 博主按:《每天一個(gè)設(shè)計(jì)模式》旨在初步領(lǐng)會(huì)設(shè)計(jì)模式的精髓,目前采用javascript(_靠這吃飯_)和python(_純粹喜歡_)兩種語(yǔ)言實(shí)現(xiàn)。誠(chéng)然,每種設(shè)計(jì)模式都...

    svtter 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<