观察者模式,从公众号群发说起

每个人应该都订阅了不少微信公众号,那你有没有注意到微信公众号的消息呢?你订阅的公众号号主每发布一篇文章,你都会主动的接收到文章的推送,并不需要你点开每个订阅的公众号一一查看有没有更新,是不是觉得有点意思?感兴趣?那就接着往下看吧,因为接下来我们要模拟公众号群发的场景。

要模拟公众号群发,首先需要简单的了解一下公众号的特点,对于公众号的特点,我总结了以下三点:

  • 每个公众号会有多名订阅者,公众号跟订阅者在某种层面上是一对多的关系
  • 只有订阅者才能在公众号发布新文章时,会及时接收到推送通知,没有订阅公众号的阅读者不会接收到文章推送通知。
  • 每个订阅者都依赖于公众号号主,只有公众号号主发布文章,订阅者才有文章查看

现在业务场景我们大概知道了,那就开始动手编写我们的业务吧,我们先从公众号号主开始。

对于公众号号主,我们先理解一下公众号特点的第二点:只有订阅者才能在公众号发布新文章时,会及时接收到推送通知,没有订阅公众号的阅读者不会接收到文章推送通知。这个特点说明在公众号号主这边维护者订阅者的列表,在每次发布文章时会通知列表中的每一个订阅者告诉他们有新文章了。如果号主没有订阅者列表,那怎么知道需要通知哪些人呢?对于这个订阅者列表,号主肯定有增删的权利,毕竟这个公众号你说了算。根据上面分析的,我们给号主做出一个抽象,我们建立一个抽象的Author类。Author类具体设计如下:

/*** 号主抽象类*/
public interface Author {// 添加关注者void addReader(Reader reader);// 删除关注者void deleteReader(Reader reader);// 通知关注者void notifyReader();// 写文章void writeArticle(String article);
}

在我们的场景中号主主要有添加订阅者、删除订阅者、通知订阅者和写文章的功能,号主有了,接下来就是我们的订阅者,订阅者在我们的场景中就比较简单了,只有一个阅读的功能,我们定义一个阅读者抽象类ReaderReader类的具体设计如下:

/*** 阅读者接口*/
public interface Reader {// 阅读文章void reader(String authorName,String article);
}

号主和阅读者的接口都定义好了,下面我们就需要真正的号主和订阅者了。我们建立我们第一个号主平头哥PingtougeAuthorPingtougeAuthor类的设计如下:

/*** @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下的ObservableObserver两个类,有兴趣的可以去了解一下。

源代码

文章不足之处,望大家多多指点,共同学习,共同进步

最后

个人公众号

欢迎扫码添加博主微信

平头哥的技术博文

欢迎扫码关注博主微信公众号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/50041.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

推特开发者账号 学术【推特开发者文档V2系列3】——tweepy4 解决推文省略号|推文不全

关于推特开发者账号 elevated academic 请看此贴&#xff1a; 推特开发者账号申请权限 或 搜索微信公众号 twitterDeveloper 获得帮助 书接上文&#xff1a; 使用tweepy4 搜索历史推文 在使用推特 v2接口的时候&#xff0c;比如上面的文章&#xff0c;有时候会发现tweepy返…

英语积累知识(一) 2020/1/28 公众号推文翻译

2020/1/28 公众号推文翻译 翻译 This Spring Festival is doomed to be a peculiar one. Without the noise of former festivals, without visiting friends and relatives and dining together with friends, instead&#xff0c;people stay at home to amuse themselves(se…

群推王|如何引爆您的推特流量

推特营销主要吸引力在于其庞大的用户群体。它是最大的社交媒体平台之一&#xff0c;据统计每月有3.3亿活跃用户&#xff0c;为品牌知名度和增长做出了重大贡献。 尽管我们都知道推特营销的重要性&#xff0c;但是在实际运用上大家可能会遇到一些问题&#xff0c;比如您有很多粉…

微信公众号推文发布方法(内涵详细步骤)

今天又朋友专门发信息咨询微信公众号推文怎么发布以及维护方法,在大不分熟悉微信公众号发文流程的同学看来,其实是非常简单的;但是对于没有接触过这一方面的其他同学来讲,也是一件非常苦恼的事情,没有头绪。在经过一番对于朋友的指导,我也把这一流程记录在此,希望能给到…

微信公众号推文发布方法(内含详细步骤)

今天有朋友专门发信息咨询微信公众号推文怎么发布以及维护方法&#xff0c;在大部分熟悉微信公众号发文流程的同学看来&#xff0c;其实是非常简单的&#xff1b;但是对于没有接触过这一方面的其他同学来讲&#xff0c;也是一件非常苦恼的事情&#xff0c;没有头绪。在经过一番…

大模型在金融AIGC领域的前景与应用

随着大模型技术的火爆&#xff0c;人们在思考如何借助 AI 提高编程效率的同时&#xff0c;也在思考 AI 对各行各业都会带来怎样的影响。在 CSDN 与《新程序员》合作举办的「新程序员大会&#xff08;NPCon&#xff09;——AIGC 与大模型技术应用论坛」上&#xff0c;来自文因互…

刘强东终于向自己的兄弟下手了!

作者 | 胡巍巍 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 曾经有这么一位老板&#xff0c;把自己的员工当兄弟&#xff0c;称“不会开除任何一位兄弟”。 图源见水印 曾经这位老板&#xff0c;在某年的老员工授勋仪式上&#xff0c;无比仗义地说&#xff…

互联网大佬们的代码水平如何?网友:刘强东95年一个晚上赚5万

作为京东集团大佬&#xff0c;刘强东备受关注。互联网界的大佬&#xff0c;很多都是程序员出身&#xff0c;或者会写代码&#xff0c;就像雷军、马化腾、李彦宏、周鸿祎等&#xff0c;几乎都是编程高手。有人问刘强东的代码水平如何? 关于这个问题&#xff0c;得到了很多网友的…

刘强东的代码水平到底有多强?30年前就已破万!

在人工智能机器学习的领域中&#xff0c;目前最火的莫过于计算机视觉了&#xff0c;这项技术一直广受关注&#xff0c;而其中的目标检测是计算机视觉领域中最常见的问题之一。 从去年的 YOLOv4 发布后&#xff0c;目标检测框架被问的最多的问题就是&#xff1a;“有没有同学复现…

刘强东个人标签太明显,京东没有二号人物

作者 | 赵陈婷 不管个人形象上是利好还是利空&#xff0c;爱公开发声的刘强东的一举一动经常直接影响着京东的股价。不过这个周一&#xff0c;京东赶上了美国劳动节美股休市。 可以说&#xff0c;作为创始人刘强东很大程度上是和他所创办的企业京东划上等号的。这家1998年成立的…

拼多多面试官没想到ThreadLocal我用得这么溜,人直接傻掉

点赞再看&#xff0c;养成习惯&#xff0c;微信搜一搜【敖丙】关注这个互联网苟且偷生的程序员。 本文 GitHub https://github.com/JavaFamily 已收录&#xff0c;有一线大厂面试完整考点、资料以及我的系列文章。 开场白 张三最近天气很热心情不是很好&#xff0c;所以他决定…

大数据面试吹牛草稿V2.0

面试吹牛之前先打个草稿&#xff01; 本文首发于微信公众号【五分钟学大数据】&#xff0c;公众号上有很多大数据学习方法&#xff0c;学习文档&#xff0c;最全的大数据面试八股文等 各位面试官好! 1. 我叫 xxx&#xff0c;毕业于 xxx&#xff0c;之前在 xxx 公司待了 1 年多&…

抢程序员饭碗?自动写代码的Deep TabNine真如此神奇?

作者 | James Vincent等 编译 | 夕颜 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 导读&#xff1a;在过去的一年中&#xff0c;AI 生成书面文字的能力大大提高。通过扫描庞大的文本数据集&#xff0c;机器学习软件可以生成从短篇小说到歌词的各种令人信服的样本…

刘强东的代码水平如何?网友:当年一晚赚5万

作为京东集团大佬&#xff0c;刘强东备受关注。互联网界的大佬&#xff0c;很多都是程序员出身&#xff0c;或者会写代码&#xff0c;就像雷军、马化腾、李彦宏、周鸿祎等&#xff0c;几乎都是编程高手。于是有人问道&#xff0c;刘强东的代码水平如何? 关于这个问题&#xff…

【我惊呆了】Chatgpt比程序员还懂代码

Chatgpt竟然比程序员还懂代码&#xff1f;这个AI让我惊呆了 你有没有遇到过这样的情况&#xff1a;你在写代码的时候&#xff0c;突然发现一个bug&#xff0c;但是你怎么也找不出原因&#xff0c;只能无奈地看着程序崩溃。你想要求助&#xff0c;但是同事都很忙&#xff0c;网上…

刘强东不学编程,今天很可能没有京东......一位码农的发家致富史

公元前216年&#xff0c;16岁的项羽随叔父离开老家宿迁&#xff0c;踏上了西楚霸王之路。2200多年后&#xff0c;“大强子”带着村里人为他凑的500块钱和76个茶叶蛋&#xff0c;离开老家宿迁&#xff0c;来到了中国人民大学社会学院。他跟朋友说&#xff1a;我就是想当官&#…

afl-fuzz.c 源码全分析

afl-fuzz.c 源码全分析 picasso big sb 这是整个 afl 项目的核心&#xff0c;本文根据 clion 调试的执行顺序进行分析。 首先使用 afl-gcc 编译并插桩程序&#xff1a; afl-gcc -g test1.c -o afl-test然后设置 afl-fuzz 的参数&#xff0c;fuzz_in 和 fuzz_out 是新建的&a…

C++高级编程-高级特性

临时总结&#xff1a; <utility> std::move 获得右值引用 奇形怪状的函数 1.传统函数 void f&#xff08;int a&#xff09;{}2.<functional> bind bind( F&& f, Args&&... args ); 参数 f - 可调用 (Callable) 对象&#xff08;函数对象、指向函…

Vue——May(1)

VUE 一、vue基础1.1 引用1.2 基础应用1.3 模板语法1.4 数据处理1.5 el与 .$mount1.6 data的函数式写法1.7 架构模型——MVVM模型1.8 数据代理Object.defineproperty1.9 理解数据代理1.10 事件处理1.10.1 参数1.10.2 this1.10.3 简写1.10.4 传参 1.11 事件修饰符1.12 键盘事件1.…

三次输错密码后,系统是怎么做到不让我继续尝试的?

故事背景&#x1f34a; 忘记密码这件事&#xff0c;相信绝大多数人都遇到过&#xff0c;输一次错一次&#xff0c;错到几次以上&#xff0c;就不允许你继续尝试了。 但当你尝试重置密码&#xff0c;又发现新密码不能和原密码重复&#xff1a; 相信此刻心情只能用一张图形容&a…