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

概念

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

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


发布订阅模式角色

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

代码实现

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

发布者->

  • 抽象发布者基类
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实现发布订阅》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值