觀察者模式介紹
觀察者模式又被叫做發佈訂閱模式。觀察者模式在Java中非常的常見,比如說Spring中的事件監聽設計就是觀察者模式,再比如說Redis、kafka的發佈訂閱功能就是觀察者模式。
應用場景
觀察者模式在應用上非常廣泛,比如訂閱推送,發佈訂閱功能,聊天場景,微信公衆號訂閱等非常多。這個模式說白了就是:被觀察者(發佈者)生產內容,觀察者(訂閱者)獲取內容。比如說訂閱推送,假如我的博客發了一篇新的文章,那麼那些關注我的人就會收到推送的消息。再比如說51CTO的付費專欄,如果專欄作者發佈了新的專欄內容,那麼那些訂閱了該作者該專欄的人就會收到專欄推送的消息。而聊天分爲一對一和一對多,一對一是私聊模式,而一對多是羣聊模式,他們都是觀察者模式。
觀察者模式類圖
實現訂閱專欄功能
1.Observer接口
/**
* @ClassName Observer
* @Description TODO:描述該接口職責
* @Author ckmike
* @Date 18-12-7 下午3:00
* @Version 1.0
* @Copyright ckmike
**/
public interface Observer {
void update(String message);
}
2.Observerable接口
/**
* @ClassName Observerable
* @Description TODO:描述該接口職責
* @Author ckmike
* @Date 18-12-7 下午2:56
* @Version 1.0
* @Copyright ckmike
**/
public interface Observerable {
// 註冊觀察者
void register(Observer observer);
// 註銷觀察者
void remove(Observer observer);
void notifyObserver();
}
3.SubscriptionChannel類
/**
* SubscriptionChannel 簡要描述
* <p> TODO:描述該類職責 </p>
*
* @author ckmike
* @version 1.0
* @date 18-12-7 下午3:04
* @copyright ckmike
**/
public class SubscriptionChannel implements Observerable{
List<Observer> observers;
private String message;
public SubscriptionChannel() {
this.observers = new ArrayList<Observer>();
}
@Override
public void register(Observer observer) {
this.observers.add(observer);
}
@Override
public void remove(Observer observer) {
this.observers.remove(observer);
}
@Override
public void notifyObserver() {
// 通知所有observer
for(Observer observer: this.observers){
observer.update(message);
}
}
public void sendMessage(String message) {
this.message = message;
System.out.println("專欄作者更新專欄文章......");
// 調用通知所有訂閱者
notifyObserver();
}
}
4.User類
/**
* User 簡要描述
* <p> TODO:描述該類職責 </p>
*
* @author ckmike
* @version 1.0
* @date 18-12-7 下午3:13
* @copyright ckmike
**/
public class User implements Observer {
private String name;
private String message;
public User(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
// 這裏應該寫到數據庫中的,但我們這裏就直接輸出吧,方便
read();
}
public void read() {
System.out.println(name+"收到推送消息:"+this.message);
}
}
5.測試用例
/**
* Test 簡要描述
* <p> TODO:描述該類職責 </p>
*
* @author ckmike
* @version 1.0
* @date 18-12-7 下午3:19
* @copyright ckmike
**/
public class Test {
public static void main(String[] args) {
// 訂閱專欄
SubscriptionChannel channel = new SubscriptionChannel();
// 三個用戶
Observer user = new User("Mike");
Observer user1 = new User("William");
Observer user2 = new User("Crane");
// 用戶訂閱專欄,開啓一個線程進行訂閱
new Thread(()->{
// 假設讀者訂閱付費的間隔是10s
try {
channel.register(user);
TimeUnit.SECONDS.sleep(5);
channel.register(user1);
TimeUnit.SECONDS.sleep(5);
channel.register(user2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
// 專欄作者線程進行發佈文章,每隔一秒發佈一篇文章
new Thread(()->{
int i = 1;
while (true){
channel.sendMessage("JAVA設計模式之觀察者模式!-第"+i+"章");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
if(i>5){
break;
}
}
}).start();
// 中途有用戶退出訂閱專欄,同時有人加入訂閱
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(7);
channel.remove(user1);
TimeUnit.SECONDS.sleep(5);
channel.register(new User("Nill"));
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
那麼到這裏我們就實現了訂閱專欄消息推送。是不是很簡單。那麼我這裏再給大家提供兩個思考問題:1.如何讓後來訂閱的讀者能夠收到作者之前發佈的消息呢?2.Spring的事件監聽是如何實現的呢?如果你想到了歡迎在下面留言分析,和大家討論喲。好!打完收工!