设计模式入门--发布订阅模式

2024-08-24 02:58

本文主要是介绍设计模式入门--发布订阅模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概念

首先说明一下,发布-订阅模式并不等同于观察者模式,这两者是有区别的。举例说明,用户直接向出版社订阅杂志,出版社直接把杂志发送给订阅杂志的用户,这种场景就是观察者模式。而发布-订阅模式则不同,出版社和用户并不直接接触,用户是向邮局订阅杂志,出版社向邮局发布杂志后,邮局再向用户派送杂志。也就是说,发布-订阅模式是有一个中转调度中心的。如下图:

上图发布订阅模式进行抽象如下图,借图一用:


发布订阅模式角色

  • 发布者:消息或者说主题的生产者。
  • 订阅者:订阅消息或主题的消费者。
  • 调度中心/消息管理器:生产者发布消息与消费者订阅消息的中转站,调度作用。
  • 主题:也称消息,生产者生产与消费者使用的内容。

代码实现

案例场景:拓展《设计模式入门–观察者模式》案例二场景(资讯网站每天给注册用户推送新闻)为:很多自媒体作者向资讯网站投内容,文章被采用后,适时给注册用户推送文章。作者是消息发布者,注册用户是订阅者,调度中心是网站平台,主题则为内容(文章、广告、活动)。
思路:其实就是实现上述四个角色,这里以最简单的方式实现。
发布者:能够向平台提交内容
订阅者:能够从平台获取推送的内容、然后读内容
内容:文章、广告、活动,就是一个封装的实体类
调度中心:能够存储发布者提交的内容,能够添加、删除订阅者,能够推送消息给订阅者

发布者->

  • 抽象发布者基类
package learn.publishsubscribe.example;/*** 抽象发布者* Created by chao.du on 2018/2/1.*/
public interface BaseAuthor<T> {/*** 发布消息(作者向网站提交文章)* @param contentHelper  消息管理器,订阅器*/void pushlishContent(ContentHelper contentHelper,T content);}
  • 具体发布者
package learn.publishsubscribe.example;/*** 具体发布者1,作者1* Created by chao.du on 2018/2/1.*/
public class AuthorA<T extends BaseContent> implements BaseAuthor<T> {private String name;public void pushlishContent(ContentHelper contentHelper,T content) {contentHelper.publishContentToQueue(content);}public AuthorA(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
/*** 具体发布者2,作者2* Created by chao.du on 2018/2/1.*/
public class AuthorB<T extends BaseContent> implements BaseAuthor<T> {private String name;public AuthorB(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public void pushlishContent(ContentHelper contentHelper,T content) {contentHelper.publishContentToQueue(content);}}

订阅者->

  • 抽象订阅者基类
package learn.publishsubscribe.example;/*** 抽象订阅者* Created by chao.du on 2018/2/1.*/
public abstract class BaseReader {/*** 消息*/protected BaseContent content;/*** 读者名字*/protected String name;public BaseReader(String name) {this.name = name;}/*** 订阅消息(注册用户向网站订阅文章)* @param contentHelper  消息管理器,订阅器*/void subscribeContent(ContentHelper contentHelper){contentHelper.addReader(this);}/*** 收到内容处理器推送的消息(注册用户接手某作者的创作内容)* @param content 文章*/void receiveContent(BaseContent content){this.content=content;String title=null;if(content instanceof Article){title=((Article) content).getTitle();}else if(content instanceof Advertisement){title=((Advertisement) content).getTitle();}else{title=((Activity) content).getTitle();}System.out.println(this.name+":收到来自【"+this.content.getWriteBy()+"】的"+this.content.getContentType()+"【"+title+"】");this.readContent(this.content);}/*** 收到消息,进行后续逻辑(读消息)* @param content*/abstract void  readContent(BaseContent content);
}
  • 具体订阅者
package learn.publishsubscribe.example;/*** 具体订阅者,注册者1* Created by chao.du on 2018/2/1.*/
public class Reader1 extends BaseReader {public Reader1(String name) {super(name);}public void readContent(BaseContent content) {System.out.println(this.name+"----这篇文章我读了1111");}
}package learn.publishsubscribe.example;/*** 具体订阅者,注册者2* Created by chao.du on 2018/2/1.*/
public class Reader2 extends BaseReader {public Reader2(String name) {super(name);}public void readContent(BaseContent content) {System.out.println(this.name+"----这篇文章我读了2222");}
}package learn.publishsubscribe.example;/*** 具体订阅者,注册者3* Created by chao.du on 2018/2/1.*/
public class Reader3 extends BaseReader {public Reader3(String name) {super(name);}public void readContent(BaseContent content) {System.out.println(this.name+"----这篇文章我读了3333");}
}

消息->

  • 消息基类
package learn.publishsubscribe.example;import java.util.Date;/*** 消息类,主题,内容类型:文章、广告、活动等* Created by chao.du on 2018/2/1.*/
public abstract class BaseContent {protected String contentType;protected Date createTime;protected String writeBy;public BaseContent() {this.createTime=new Date();}public BaseContent(String contentType) {this.contentType=contentType;this.createTime=new Date();}public BaseContent(String contentType, String writeBy) {this.contentType=contentType;this.writeBy=writeBy;this.createTime=new Date();}public String getContentType() {return contentType;}public Date getCreateTime() {return createTime;}public String getWriteBy() {return writeBy;}public void setWriteBy(String writeBy) {this.writeBy = writeBy;}
}
  • 具体消息类
package learn.publishsubscribe.example;/*** 内容--文章类* Created by chao.du on 2018/2/1.*/
public class Article extends BaseContent {/*** 标题*/private String title;/*** 标签*/private String tag;/*** 简介*/private String descrition;/*** 正文*/private String content;public Article() {super("文章");}public Article(String writeBy, String title, String tag, String descrition, String content) {super("文章",writeBy);this.title = title;this.tag = tag;this.descrition = descrition;this.content = content;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getTag() {return tag;}public void setTag(String tag) {this.tag = tag;}public String getDescrition() {return descrition;}public void setDescrition(String descrition) {this.descrition = descrition;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}}package learn.publishsubscribe.example;/*** 内容--广告类* Created by chao.du on 2018/2/1.*/
public class Advertisement extends BaseContent {/*** 广告标题*/private String title;/*** 广告banner地址*/private String banner;/*** 广告描述*/private String descrtion;public Advertisement() {super("广告");}public Advertisement(String writeBy, String title, String banner, String descrtion) {super("广告",writeBy);this.title = title;this.banner = banner;this.descrtion = descrtion;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getBanner() {return banner;}public void setBanner(String banner) {this.banner = banner;}public String getDescrtion() {return descrtion;}public void setDescrtion(String descrtion) {this.descrtion = descrtion;}
}package learn.publishsubscribe.example;import java.util.Date;/*** 内容--活动类* Created by chao.du on 2018/2/1.*/
public class Activity extends BaseContent {/*** 活动标题*/private String title;/*** 活动介绍*/private String content;/*** 活动时间*/private Date date;public Activity() {super("活动");}public Activity(String title, String content, Date date) {super("活动");this.title = title;this.content = content;this.date = date;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public Date getDate() {return date;}public void setDate(Date date) {this.date = date;}
}

调度中心->

package learn.publishsubscribe.example;import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;/*** 消息管理器,主题调度中心,网站文章处理器* Created by chao.du on 2018/2/1.*/
public class ContentHelper{/*** 内容调度器注册订阅内容的读者(网站注册者)容器*/private List<BaseReader> readerList=new ArrayList<BaseReader>();/*** 发布者发布消息的消息存储队列*/private Queue<BaseContent> queue = new LinkedList();public ContentHelper() {}public ContentHelper(List<BaseReader> readerList) {this.readerList = readerList;}/*** 向消息队列添加消息(供发布者发布信息调用使用)* @param content*/public void publishContentToQueue(BaseContent content){this.queue.offer(content);for(BaseReader reader:readerList){reader.receiveContent(content);}}/*** 向订阅者推送消息(供订阅者获取内容处理器推送的消息,订阅者调用)* @return*/public void pushContentFromQueue(){for (BaseReader reader:readerList){reader.receiveContent(this.queue.poll());}}/*** 添加订阅者*/public void addReader(BaseReader reader){this.readerList.add(reader);}/*** 删除订阅者*/public void removeReader(BaseReader reader){this.removeReader(reader);}
}

客户端->

package learn.publishsubscribe.example;/*** 场景:很多作者向资讯平台提交消息内容(文章、广告、活动),资讯平台向平台注册用户推送消息内容* Created by chao.du on 2018/2/2.*/
public class Client {public static void main(String[] args) {//内容处理器ContentHelper contentHelper=new ContentHelper();//订阅人,订阅消息new Reader1("小明").subscribeContent(contentHelper);new Reader2("小张").subscribeContent(contentHelper);new Reader3("小花").subscribeContent(contentHelper);//发布人,发布消息new AuthorA("美食博主").pushlishContent(contentHelper,new Article("美食博主","红烧肉绝佳菜谱","红烧肉","很好的红烧肉菜谱","步骤一、二、三"));new AuthorB("广告人").pushlishContent(contentHelper,new Advertisement("广告人","营销黄金法则","http://www.baidu.com/1.jpg","学会营销。。。。。"));}
}

运行结果->
这里写图片描述

github代码


参考资料:

1、《订阅消息模式》

2、《观察者模式与发布、订阅模式》

3、《java实现发布订阅》

这篇关于设计模式入门--发布订阅模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

MySQL DQL从入门到精通

《MySQLDQL从入门到精通》通过DQL,我们可以从数据库中检索出所需的数据,进行各种复杂的数据分析和处理,本文将深入探讨MySQLDQL的各个方面,帮助你全面掌握这一重要技能,感兴趣的朋友跟随小... 目录一、DQL 基础:SELECT 语句入门二、数据过滤:WHERE 子句的使用三、结果排序:ORDE

Redis Cluster模式配置

《RedisCluster模式配置》:本文主要介绍RedisCluster模式配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录分片 一、分片的本质与核心价值二、分片实现方案对比 ‌三、分片算法详解1. ‌范围分片(顺序分片)‌2. ‌哈希分片3. ‌虚

RabbitMQ工作模式中的RPC通信模式详解

《RabbitMQ工作模式中的RPC通信模式详解》在RabbitMQ中,RPC模式通过消息队列实现远程调用功能,这篇文章给大家介绍RabbitMQ工作模式之RPC通信模式,感兴趣的朋友一起看看吧... 目录RPC通信模式概述工作流程代码案例引入依赖常量类编写客户端代码编写服务端代码RPC通信模式概述在R