观察者模式,从公众号群发说起
每个人应该都订阅了不少微信公众号,那你有没有注意到微信公众号的消息呢?你订阅的公众号号主每发布一篇文章,你都会主动的接收到文章的推送,并不需要你点开每个订阅的公众号一一查看有没有更新,是不是觉得有点意思?感兴趣?那就接着往下看吧,因为接下来我们要模拟公众号群发的场景。
要模拟公众号群发,首先需要简单的了解一下公众号的特点,对于公众号的特点,我总结了以下三点:
- 每个公众号会有多名订阅者,公众号跟订阅者在某种层面上是一对多的关系
- 只有订阅者才能在公众号发布新文章时,会及时接收到推送通知,没有订阅公众号的阅读者不会接收到文章推送通知。
- 每个订阅者都依赖于公众号号主,只有公众号号主发布文章,订阅者才有文章查看
现在业务场景我们大概知道了,那就开始动手编写我们的业务吧,我们先从公众号号主开始。
对于公众号号主,我们先理解一下公众号特点的第二点:只有订阅者才能在公众号发布新文章时,会及时接收到推送通知,没有订阅公众号的阅读者不会接收到文章推送通知。这个特点说明在公众号号主这边维护者订阅者的列表,在每次发布文章时会通知列表中的每一个订阅者告诉他们有新文章了。如果号主没有订阅者列表,那怎么知道需要通知哪些人呢?对于这个订阅者列表,号主肯定有增删的权利,毕竟这个公众号你说了算。根据上面分析的,我们给号主做出一个抽象,我们建立一个抽象的Author
类。Author
类具体设计如下:
/*** 号主抽象类*/
public interface Author {// 添加关注者void addReader(Reader reader);// 删除关注者void deleteReader(Reader reader);// 通知关注者void notifyReader();// 写文章void writeArticle(String article);
}
在我们的场景中号主主要有添加订阅者、删除订阅者、通知订阅者和写文章的功能,号主有了,接下来就是我们的订阅者,订阅者在我们的场景中就比较简单了,只有一个阅读的功能,我们定义一个阅读者抽象类Reader
,Reader
类的具体设计如下:
/*** 阅读者接口*/
public interface Reader {// 阅读文章void reader(String authorName,String article);
}
号主和阅读者的接口都定义好了,下面我们就需要真正的号主和订阅者了。我们建立我们第一个号主平头哥PingtougeAuthor
,PingtougeAuthor
类的设计如下:
/*** @author 平头哥* @title: PingtougeAuthor* @projectName observer* @description: 号主平头哥* @date 2019/9/1817:50*/
public class PingtougeAuthor implements Author{// 订阅者列表private Vector<Reader> readers ;// 作者名称private String name;// 文章private String article;public PingtougeAuthor(String name){this.name = name;this.readers = new Vector<>();}/*** 添加关注者* @param reader*/@Overridepublic void addReader(Reader reader) {if (readers.contains(reader)) return;readers.add(reader);}/*** 移除关注者* @param reader*/@Overridepublic void deleteReader(Reader reader) {readers.remove(reader);}/*** 通知关注者*/@Overridepublic void notifyReader() {for (Reader reader:readers){reader.reader(name,article);}}/*** 写文章* @param article*/@Overridepublic void writeArticle(String article){this.article = article;notifyReader();}
}
我们在建立王山、张三、李四三个订阅者,他们的具体设计如下:
/*** 订阅者王山*/
public class WangSanReader implements Reader{private String name;public WangSanReader(String name){this.name = name;}@Overridepublic void reader(String authorName,String article) {System.out.println(name+" 阅读了 "+authorName+" 发布的 "+article+" 文章");}
}
/*** 订阅者张三*/
public class ZhangsanReader implements Reader{private String name;public ZhangsanReader(String name){this.name = name;}@Overridepublic void reader(String authorName,String article) {System.out.println(name+" 阅读了 "+authorName+" 发布的 "+article+" 文章");}
}
/*** 订阅者者李四*/
public class LiSiReader implements Reader{private String name;public LiSiReader(String name){this.name = name;}@Overridepublic void reader(String authorName,String article) {System.out.println(name+" 阅读了 "+authorName+" 发布的 "+article+" 文章");}
}
号主和订阅者都有了,万事俱备只欠东风,那我们就来进行我们第一次场景模拟,在这次模拟中,订阅者张三、王山订阅了平头哥的公众号,李四没有订阅平头哥的公众号。按照我们的设想平头哥发布文章时,张三、王山可以接收到文章推送通知,李四不会接收到文章推送通知。编写我们的第一个模拟类:
public class App {public static void main(String[] args) {PingtougeAuthor pingtougeAuthor = new PingtougeAuthor("平头哥");WangSanReader wangSanReader = new WangSanReader("王山");ZhangsanReader zhangsanReader = new ZhangsanReader("张三");LiSiReader liSiReader = new LiSiReader("李四");// 王山订阅了平头哥的公众号pingtougeAuthor.addReader(wangSanReader);// 张三订阅了平头哥的公众号pingtougeAuthor.addReader(zhangsanReader);pingtougeAuthor.writeArticle("看完这篇你还不知道这些队列,我这些图白作了");}
}
测试结果:
从测试结果中,我们可以看出张三、王山接收到了平头哥发布文章的推送通知,李四没有接收到,符合我们的预期。
接下来我们进行第二次模拟,由于平头哥最近发了不少干货,李四决定也关注平头哥的公众号,所以我们对模拟类进行了修改,修改后的模拟类如下:
public class App {public static void main(String[] args) {PingtougeAuthor pingtougeAuthor = new PingtougeAuthor("平头哥");WangSanReader wangSanReader = new WangSanReader("王山");ZhangsanReader zhangsanReader = new ZhangsanReader("张三");LiSiReader liSiReader = new LiSiReader("李四");// 王山订阅了平头哥的公众号pingtougeAuthor.addReader(wangSanReader);// 张三订阅了平头哥的公众号pingtougeAuthor.addReader(zhangsanReader);
//
// pingtougeAuthor.writeArticle("看完这篇你还不知道这些队列,我这些图白作了");// 李四也订阅平头哥的公众号pingtougeAuthor.addReader(liSiReader);pingtougeAuthor.writeArticle("实现 Java 本地缓存,该从这几点开始");}
}
测试结果:
这次三个订阅者都接收到了平头哥发布文章的推送通知。关注了平头哥的公众号有一段时间后,张三觉得平头哥的公众号不适合自己,于是就取关了平头哥的公众号,这是我们要模拟的第三个场景,我们对模拟类进行修改,修改后的模拟类如下:
public class App {public static void main(String[] args) {PingtougeAuthor pingtougeAuthor = new PingtougeAuthor("平头哥");WangSanReader wangSanReader = new WangSanReader("王山");ZhangsanReader zhangsanReader = new ZhangsanReader("张三");LiSiReader liSiReader = new LiSiReader("李四");// 王山订阅了平头哥的公众号pingtougeAuthor.addReader(wangSanReader);// 张三订了平头哥的公众号pingtougeAuthor.addReader(zhangsanReader);
//
// pingtougeAuthor.writeArticle("看完这篇你还不知道这些队列,我这些图白作了");// 李四订了平头哥的公众号pingtougeAuthor.addReader(liSiReader);// pingtougeAuthor.writeArticle("实现 Java 本地缓存,该从这几点开始");// 张三取关了平头哥的公众号pingtougeAuthor.deleteReader(zhangsanReader);pingtougeAuthor.writeArticle("实观察者模式,从微信公众号说起");}
}
测试结果:
张三取关之后,平头哥发布的文章,他将不会再接收到推送通知。在上面公众号群发的模拟场景中,我们使用到了一种设计模式,叫做观察者模式,那今天我们就一起来简单的了解一下观察者模式。
观察者模式定义
观察者模式又叫发布-订阅模式,发布-订阅模式大家应该非常熟悉了吧,消息中间件就是发布-订阅模式,观察者模式主要也是应用在消息中间件。观察这模式定义了一种一对多的依赖关系让多个订阅者同时监听某一个对象主题,这个主题对象在状态发生变化时,会通知所有的订阅者,让他们自己更新自己。这些特点在我们的模拟场景中基本上都体现出来了,如果你对这些有疑问,可以多看我们的模拟场景。
观察者的结构
- 抽象主题(Subject)角色:抽取出了主题所需要定义的接口,比如我们的
Author
类 - 具体主题(Concrete Subject)角色:具体的主题实现者,该类必须继承抽象主题,比如我们的
PingtougeAuthor
- 抽象观察者(Observer)角色:观察者抽象类,定义观察者需要的接口,比如我们的
Reader
- 具体观察者(Concrete Observer)角色:具体的观察者,做这具体业务的类,比如我们的三个订阅者
观察者的 UML 图
观察者模式的优点
- 主题与观察者之间松耦合
- 支撑广播通信:一条消息可以通知给多个人
- 建立一条触发链:A触发B,B触发C,一条触发链,不过这个需要注意的地方很多
观察者的缺点
- 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率
- 如果采用顺序通知,当某个观察者卡住了,其他的观察者将无法接收到通知
- 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
观察者模式差不多就这些内容,相对来说比较容易理解,另外多说一句,在JDK中已经内置了观察者模式,在java.util
下的Observable
、Observer
两个类,有兴趣的可以去了解一下。
源代码
文章不足之处,望大家多多指点,共同学习,共同进步
最后
观察者模式,从公众号群发说起相关推荐
- 公众号群发文章支持添加小程序
微信小程序深夜凌晨放大招,公众号群发文章支持添加小程序,以下是微信公众平台的公告:为了方便用户在阅读文章时使用公众号提供的服务,公众号群发文章支持添加小程序. 公众号可将已关联的小程序添加到群发文章的 ...
- python公众号留言功能_Python实现的微信公众号群发图片与文本消息功能实例详解...
本文实例讲述了Python实现的微信公众号群发图片与文本消息功能.分享给大家供大家参考,具体如下: 在微信公众号开发中,使用api都要附加access_token内容.因此,首先需要获取access_ ...
- C#实现微信公众号群发消息(解决一天只能发一次的限制)
经过几天研究网上的代码和谢灿大神的帮忙,今天终于用C#实现了微信公众号群发消息,现在整理一下. 总体思路:1.首先必须要在微信公众平台上申请一个公众号. 2.然后进行模拟登陆.(由于我对http传输原 ...
- 微信公众号计算机编程,微信公众号群发文章怎么添加小程序?-电脑教程
2017年4月20日微信发布公告称,微信公众平号群发文章支持添加小程序功能,这对于推广小程序来说,无疑是不错的途径.那么微信公众号群发文章怎么添加小程序?以下是华强电子网带来的详细教程. 微信公众号群 ...
- PHP公众号群发用户过多,公众号四次群发用完怎么办?
月末将至,很多运营者向小编求助,公众号四次群发用完怎么办?其实这个问题并不难,因为是服务号嘛,大家群发次数都一样, 每个月只有固定的四次.但是服务号群发用完之后可以借助新锐群发宝的模板消息实现增加群发 ...
- 微信公众号发送小程序卡片_微信公众号群发文章支持添加小程序卡片
2017年4月20日微信发布公告称,微信公众平号群发文章支持添加小程序功能,这对于推广小程序来说,无疑是不错的途径.那么微信公众号群发文章怎么添加小程序?下面爱站技术频道的小编带来的详细教程. 微信公 ...
- 微信公众号群发图文消息
微信公众号群发图文消息 说明:本demo是基于CoffeeWx框架进行编写的,主要是为了以后复习,如有在学习中有疑问,请参考https://gitee.com/skysong/coffeewx-adm ...
- python公众号留言功能详情_Python实现的微信公众号群发图片与文本消息功能实例详解...
本文实例讲述了Python实现的微信公众号群发图片与文本消息功能.分享给大家供大家参考,具体如下: 在微信公众号开发中,使用api都要附加access_token内容.因此,首先需要获取access_ ...
- 利用python 实现微信公众号群发图片与文本消息功能
在微信公众号开发中,使用api都要附加access_token内容.因此,首先需要获取access_token.如下: #获取微信access_token def get_token():payloa ...
最新文章
- vc sp6 中英文和补丁下载地址
- 计算机临床医学自动化哪个好,大学专业难度排行前十名,临床医学位列第二
- ios中静态库的创建和使用、制作通用静态库(Cocoa Touch Static Library)
- unbuntu使用经典界面
- php获取linux是几核的,linux下怎么查看机器cpu是几核的
- c语言双精度百分号,C语言输出百分号%的方法和示例
- 对于局部变量_浅谈Shell函数中全局变量和局部变量
- 一个面试题关于变量的生命周期
- java获取时间日期代码
- app = Flask(__name__) 是个什么东西
- 系统架构设计师与系统分析师历年实体分析与解答下载_架构设计的本质
- 自定义windows快捷键(autohotkey)的办法
- 用单片机测量流体流速的_基于LMS算法的流体流速测量系统
- 论运营型CRM和分析型CRM
- 零基础学IT选择软件测试有前途吗?
- Ghost之远程终端管理
- 在线教育软件开发的目的是什么?
- apk开发软件下载!花费近一年时间整理的Android核心知识清单,含BATJM大厂
- 诓”妹妹与“旺”夫君
- 登山赛车破解无线金币实现原理分析