設計模式入門--發佈訂閱模式

概念

首先說明一下,發佈-訂閱模式並不等同於觀察者模式,這兩者是有區別的。舉例說明,用戶直接向出版社訂閱雜誌,出版社直接把雜誌發送給訂閱雜誌的用戶,這種場景就是觀察者模式。而發佈-訂閱模式則不同,出版社和用戶並不直接接觸,用戶是向郵局訂閱雜誌,出版社向郵局發佈雜誌後,郵局再向用戶派送雜誌。也就是說,發佈-訂閱模式是有一箇中轉調度中心的。如下圖:

上圖發佈訂閱模式進行抽象如下圖,借圖一用


發佈訂閱模式角色

  • 發佈者:消息或者說主題的生產者。
  • 訂閱者:訂閱消息或主題的消費者。
  • 調度中心/消息管理器:生產者發佈消息與消費者訂閱消息的中轉站,調度作用。
  • 主題:也稱消息,生產者生產與消費者使用的內容。

代碼實現

案例場景:拓展《設計模式入門–觀察者模式》案例二場景(資訊網站每天給註冊用戶推送新聞)爲:很多自媒體作者向資訊網站投內容,文章被採用後,適時給註冊用戶推送文章。作者是消息發佈者,註冊用戶是訂閱者,調度中心是網站平臺,主題則爲內容(文章、廣告、活動)。
思路:其實就是實現上述四個角色,這裏以最簡單的方式實現。
發佈者:能夠向平臺提交內容
訂閱者:能夠從平臺獲取推送的內容、然後讀內容
內容:文章、廣告、活動,就是一個封裝的實體類
調度中心:能夠存儲發佈者提交的內容,能夠添加、刪除訂閱者,能夠推送消息給訂閱者

發佈者->

  • 抽象發佈者基類
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實現發佈訂閱》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章