订阅者模式,公众号、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%的原因其实都是为了抵御日后功能需求的变化。
废话不多说了,今天的文章就到这里,衷心祝愿大家每天都有所收获。如果还喜欢今天的内容的话,请来一个三连支持吧~(点赞、关注、转发)

订阅者模式,公众号、B站、快手用了都说好!的更多相关文章
- 利用python 实现微信公众号群发图片与文本消息功能
在微信公众号开发中,使用api都要附加access_token内容.因此,首先需要获取access_token.如下: #获取微信access_token def get_token(): paylo ...
- 微信公众号token的asp.net脚本
老板让我搞一个微信公众号.好吧.前面都很EZ,直到要使用一个token验证服务器的有效性. 看了下文档,大概意思就是微信的服务器用GET请求访问你的服务器. 其中包含了signature,nonce, ...
- 通过微信公众号API复制公众号自定义菜单同时增加子菜单方法
主要的原因是再不破坏公众号以前的菜单的基础上增加自定义菜单,主要步骤如下: 1.通过微信提供的微信公众平台接口调试工具获取公众号的所有自定义菜单 网址:https://mp.weixin.qq.com ...
- 微信公众号ID也可以修改了!
差不多一年前,微信团队宣布个人类帐号一个自然年内可主动修改两次名称,那一天大家奔走相告纷纷修改成自己早就心仪的名字,有人猛然发现公众号名字改了,可ID还是xiaopipi(小屁屁)这可如何是好,洗不去 ...
- [转]微信小程序、微信公众号、H5之间相互跳转
本文转自:https://www.cnblogs.com/colorful-paopao1/p/8608609.html 转自慕课网 一.小程序和公众号 答案是:可以相互关联. 在微信公众号里可以添加 ...
- 微信小程序、微信公众号、H5之间相互跳转
转自慕课网 一.小程序和公众号 答案是:可以相互关联. 在微信公众号里可以添加小程序. 图片有点小,我把文字打出来吧: 可关联已有的小程序或快速创建小程序.已关联的小程序可被使用在自定义菜单和模版消息 ...
- python微信公众号开发学习记录
网上有很多微信公众号的开发教程,但是都是好几年前的了,而且很多都是抄袭其他人的,内容几乎一模一样.真的无语了.只好自己总结一下开发的一些简单流程. 一先去注册个微信公众号,这个就不详细说了, 二登录后 ...
- 微信公众号获取微信token
微信在公众号和小程序的开发都有开放文档一般看文档开发就行,很简单这里写一个小demo获取微信token,之后根据自己的业务获取信息处理即可 package com.demo.ccx; import o ...
- 微信公众号添加zip
微信公众号添加zip的教程 我们都知道创建一个微信公众号,在公众号中发布一些文章是非常简单的,但公众号添加附件下载的功能却被限制,如今可以使用小程序“微附件”进行在公众号中添加附件. 以下是公众号添加 ...
- 微信公众号里放XLS链接
微信公众号里放XLS链接 我们都知道创建一个微信公众号在公众号中发布一些文章是非常简单的,但公众号添加附件下载的功能却被限制,如今可以使用小程序“微附件”进行在公众号中添加附件,如:xls,word等 ...
随机推荐
- Windows安装VsCode 和Nodejs Vue
一.安装VSCode 1.在官网下载并安装VSCode https://code.visualstudio.com/Download 注意:解压到非系统盘(节约系统盘空间,也方便后面使用) 文件夹最好 ...
- [PASECA2019]honey_shop writeup
这是PASECA2019的一道web题 前端是一个蜂蜜商店,你有$1336,可以买蜂蜜和flag.但是flag要$1337,所以我们只能买蜂蜜. 一般这种题目的常规操作就是通过修改你的钱使你能够买到f ...
- 10天,从.Net转Java,并找到月薪2W的工作(二)
辞去.Net工作之后,第一天直接去星巴克学习. 研究如何入门Java,对比学习资料以及安装Ieda. 由于正版太贵,Mac又不容易破解.鼓捣半天,最后结果是,我决定用教育账号申请一年的免费IDEA. ...
- jfinal项目报java.lang.ClassNotFoundException: com.jfinal.core.JFinalFilter
在eclipse中启动jfinal项目时,项目报错如下:首先:右击项目–>Build Path–>Source查看Default output folder如果是目录/WEB-INF/cl ...
- 如何解决 ajax跨域被阻止 CORS 头缺少 'Access-Control-Allow-Origin'的问题?
已拦截跨源请求:同源策略禁止读取位于 http://192.168.1.72:8080/securityMonitor_TV/service/getTest 的远程资源. (原因:CORS 头缺少 ' ...
- int和Integer的区别?包装类?装箱?拆箱?
int和Integer的区别: 1) int是基本数据类型,直接存储的数值,默认是0; 2) Integer 是int的包装类,是个对象,存放的是对象的引用,必须实例化之后才能使用,默认是null; ...
- 包与包管理.md
软件包:源码包 RPM包 二进制包 RPM包依赖性 模块依赖查询 www.rpmfind.net umount 解除CDROM挂载 mount 挂载 umount [/dev/device ...
- 结合MATLAB、Python、R语言,在求得显著差异的边(节点对)之后,怎么画circle图
先来看看成果图: OK,开始画图: 实验背景声明:在脑影像分析中,我们首先构建脑网络,然 ...
- 7.shell脚本编程
1.shell 脚本语言的基本用法 1.1shell 脚本创建 1.格式要求:首行shebang机制 #!/bin/bash #!/usr/bin/python #!/usr/bin/perl 2.添 ...
- 实现Vue的多页签组件
在之前的博客中 关于vue的多页面标签功能,对于嵌套router-view缓存的最终无奈解决方法 有写过vue的多页签功能的解决方案 可以看到我当时那个多页签的组件还是比较简单 的,只有打开跟关闭 ...