每個人應該都訂閱了不少微信公眾號,那你有沒有注意到微信公眾號的訊息呢?你訂閱的公眾號號主每發布一篇文章,你都會主動的接收到文章的推送,并不需要你點開每個訂閱的公眾號一一查看有沒有更新,是不是覺得有點意思?感興趣?那就接著往下看吧,因為接下來我們要模擬公眾號群發的場景,
要模擬公眾號群發,首先需要簡單的了解一下公眾號的特點,對于公眾號的特點,我總結了以下三點:
- 每個公眾號會有多名訂閱者,公眾號跟訂閱者在某種層面上是一對多的關系
- 只有訂閱者才能在公眾號發布新文章時,會及時接收到推送通知,沒有訂閱公眾號的閱讀者不會接收到文章推送通知,
- 每個訂閱者都依賴于公眾號號主,只有公眾號號主發布文章,訂閱者才有文章查看
現在業務場景我們大概知道了,那就開始動手撰寫我們的業務吧,我們先從公眾號號主開始,
對于公眾號號主,我們先理解一下公眾號特點的第二點:只有訂閱者才能在公眾號發布新文章時,會及時接收到推送通知,沒有訂閱公眾號的閱讀者不會接收到文章推送通知,這個特點說明在公眾號號主這邊維護者訂閱者的串列,在每次發布文章時會通知串列中的每一個訂閱者告訴他們有新文章了,如果號主沒有訂閱者串列,那怎么知道需要通知哪些人呢?對于這個訂閱者串列,號主肯定有增刪的權利,畢竟這個公眾號你說了算,根據上面分析的,我們給號主做出一個抽象,我們建立一個抽象的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
*/
@Override
public void addReader(Reader reader) {
if (readers.contains(reader)) return;
readers.add(reader);
}
/**
* 移除關注者
* @param reader
*/
@Override
public void deleteReader(Reader reader) {
readers.remove(reader);
}
/**
* 通知關注者
*/
@Override
public void notifyReader() {
for (Reader reader:readers){
reader.reader(name,article);
}
}
/**
* 寫文章
* @param article
*/
@Override
public void writeArticle(String article){
this.article = article;
notifyReader();
}
}
我們在建立王山、張三、李四三個訂閱者,他們的具體設計如下:
/**
* 訂閱者王山
*/
public class WangSanReader implements Reader{
private String name;
public WangSanReader(String name){
this.name = name;
}
@Override
public 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;
}
@Override
public 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;
}
@Override
public 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兩個類,有興趣的可以去了解一下,
源代碼
文章不足之處,望大家多多指點,共同學習,共同進步
最后
 歡迎掃碼添加博主微信  歡迎掃碼關注博主微信公眾號轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/44335.html
標籤:設計模式
上一篇:面向切面編程AOP
下一篇:單例模式
