• 订阅者模式,公众号、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%的原因其实都是为了抵御日后功能需求的变化。

    废话不多说了,今天的文章就到这里,衷心祝愿大家每天都有所收获。如果还喜欢今天的内容的话,请来一个三连支持吧~(点赞、关注、转发

  • 相关阅读:
    优先级管理器 IPriorityManager -- ESBasic 可复用的.NET类库(14)
    对象获取器IObjectRetriever -- ESBasic 可复用的.NET类库(17)
    定时刷新缓存管理器 IRefreshableCacheManager --ESBasic 可复用的.NET类库(16)
    TopN排行榜容器 TopNOrderedContainer -- ESBasic 可复用的.NET类库(20)
    回调定时器ICallbackTimer --ESBasic 可复用的.NET类库(07)
    Linux kernel data types, alignment, compat_ioctl 数据类型,对齐问题和compat_ioctl
    ubnutu开启daytime服务
    从长春到深圳“一个人的旅行”第二篇
    多客户模式

  • 原文地址:https://www.cnblogs.com/techflow/p/14327485.html
Copyright © 2020-2023  润新知