大家好,今天和大家来聊一个新的设计模式——订阅者模式。
这个模式在我们的生活当中非常常见,可以说是几乎所有的媒体平台都用或多或少地用到了这个模式。比如公众号,我们来仔细梳理一下公众号这个平台当中的整个逻辑,会发现其实这里面一共有三方存在,这三方呈一个三角关系。
三方订阅关系
画出来的话大概是这个样子:
这张图大家应该很好理解,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%的原因其实都是为了抵御日后功能需求的变化。
废话不多说了,今天的文章就到这里,衷心祝愿大家每天都有所收获。如果还喜欢今天的内容的话,请来一个三连支持吧~(点赞、在看、转发)