訂閱者模式,公衆號、B站、快手用了都說好!

大家好,今天和大家來聊一個新的設計模式——訂閱者模式

這個模式在我們的生活當中非常常見,可以說是幾乎所有的媒體平臺都用或多或少地用到了這個模式。比如公衆號,我們來仔細梳理一下公衆號這個平臺當中的整個邏輯,會發現其實這裏面一共有三方存在,這三方呈一個三角關係。

三方訂閱關係

畫出來的話大概是這個樣子:

這張圖大家應該很好理解,TechFlow每天把新的文章發佈到公衆號平臺上,平臺會把內容推送給那些關注了TechFlow的用戶,大家正是因爲關注了TechFlow纔讀到了這篇文章。

所以在訂閱制的內容平臺當中,其實是一個三方關係,而不是讀者和作者兩方關係,平臺在當中起到了媒介的作用。只是很多時候作爲讀者,我們可能會忽略平臺的存在。

既然存在三方關係,我們在實現相關邏輯的時候就需要把這三方剝離出來,單獨實現各自的邏輯,這樣代碼的耦合性才最低,可以更加方便以後的拓展。

代碼實現

訂閱者模式其實沒有太多內容需要講,我們只需要記住一點,就是儘量讓屬於不同實體的代碼邏輯分開,而不是耦合在一起就可以了,沒有太多其他的門道。

我們先來看這個模式當中最簡單的部分,也就是Publisher(作者)這個部分。對於作者而言,它是最簡單的,因爲它能做的事情非常少,就只有發佈內容而已。當然一般現在也會有一些作者保護機制,比如說可以拉黑一些不喜歡的用戶什麼的,但這裏我們不需要考慮那麼多,只需要考慮基本功能就行了。對於作者而言,最基本的功能就是發佈內容。

代碼非常簡單,就只有幾行。

class Publisher:

    def __init__(self, msg_center):
        self.provider = msg_center

    def publish(self, msg):
        self.provider.notify(msg)

因爲作者自身是沒辦法發佈內容的,作者是把要發佈的內容上傳到平臺,平臺代替作者去發佈的。體現在這個類當中就是我們調用了provider也就是平臺去執行通知(notify)的操作,把新發布的內容推送到讀者端。

讀者端稍微複雜一點,因爲讀者不僅可以訂閱,還可以取關,並且收到了消息之後還可以打開以及一些互動。這裏我們把功能簡化,就留下了三個最基本的功能,分別是關注、取關以及操作。

class Subscriber:
    
    def __init__(self, name, msg_center):
        self.name = name
        self.provider = msg_center

    def subscribe(self, msg):
        self.provider.subscribe(msg, self)

    def unsubscribe(self, msg):
        self.provider.unsubscribe(msg, self)

    def run(self, msg):
        print('{} got {}'.format(self.name, msg))

從代碼當中我們可以看到,讀者端的操作其實也是和平臺交互。平臺是讀者和作者之間的媒介,讀者和作者之間不直接發生關聯。這其實是非常不錯的設計,如果關聯和依賴很多,就會出現要開發新功能的時候畏手畏腳,會影響其他模塊的情況發生。

最後,我們來看平臺的部分,平臺的部分其實也不復雜,只是用一個dict存儲了讀者和作者之間的訂閱關係而已。其實這裏沒必要使用setdefault,使用defaultdict會更好。

class Provider:

    def __init__(self):
        self.msg_queue = []
        self.subscribers = {}

    def notify(self, msg):
        self.msg_queue.append(msg)

    def subscribe(self, msg, subscriber):
        self.subscribers.setdefault(msg, []).append(subscriber)

    def unsubscribe(self, msg, subscriber):
        self.subscribers[msg].remove(subscriber)

    def update(self):
        # 遍歷所有的作者
        for msg in self.msg_queue:
            # 遍歷所有訂閱了msg的讀者進行推送
            for sub in self.subscribers.get(msg, []):
                sub.run(msg)
        self.msg_queue = []

這裏我把執行的測試代碼也放上來,大家感興趣可以自己試驗一下。

if __name__ == '__main__':
    message_center = Provider()
    fftv = Publisher(message_center)

    jim = Subscriber('jim', message_center)
    jim.subscribe('cartoon')

    jack = Subscriber('jack', message_center)
    jack.subscribe('music')

    gee = Subscriber('gee', message_center)
    gee.subscribe('movie')

    vani = Subscriber('vani', message_center)
    vani.subscribe('movie')

    fftv.publish('cartoon')
    fftv.publish('music')
    fftv.publish('ads')
    fftv.publish('cartoon')
    fftv.publish('cartoon')
    fftv.publish('movie')
    fftv.publish('blank')

    message_center.update()

從代碼層面來說,這個設計模式沒有太多的難度,主要是一種解耦的思想。這一個思想很重要,在實際開發當中,我們決不能僅僅滿足於實現產品經理的功能,因爲產品經理往往是不懂這些系統之間架構和軟件工程的。我們之所以需要設計模式只有30%的原因是爲了更好的效率以及更簡潔的代碼,剩下70%的原因其實都是爲了抵禦日後功能需求的變化。

廢話不多說了,今天的文章就到這裏,衷心祝願大家每天都有所收穫。如果還喜歡今天的內容的話,請來一個三連支持吧~(點贊、關注、轉發

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章