1 概述
觀察者模式(observer Pattern),也叫發佈-訂閱模式,是一種很重要的行爲模式,它被廣泛運用在異步編程之中,可以說是異步編程的基礎。
2 觀察者模式
當我們需要關注某個對象的狀態時,可以不斷地輪詢,查看狀態是否變化,這也就是我們熟知的同步方式。然而這樣的方式效率很低,在對象狀態真正變化之前,任何的檢查都是對服務器資源的浪費。更好的方法是,當對象狀態改變的時候,可以有一種通知機制,告訴別人狀態發生了變化。觀察者模式,正是實現這種機制的關鍵。
觀察者模式中,觀察者可以註冊到自己感興趣的被觀察對象上,當被觀察對象的狀態發生變化,或某個事件放生時,逐個調用觀察者的方法來通知它們。這種異步的方式,很大程度上提高了運行效率
現實生活中,觀察者模式也很常見。比如網購了一件商品,我們不用時不時地去收貨點查看快遞有沒有到,而是當收到“商品已送達”的短信的時候,直接去取就行。此例中,當我們購買商品的時候,相當於關注了快遞的狀態,當狀態變爲“已送達”的時候,我們會得到通知。
3 案例
舉一個代碼案例。當我們關注了某個公衆號之後,便可以收到公衆號的文章推送,這其實就是典型的觀察者模式的例子:
public interface Observable<T> {
void addSubscriber(Observer observer);
void removeSubscriber(Observer observer);
void publish(T object);
}
public class PublicAccount implements Observable<Article> {
private String name;
private Collection<Observer> subscribers;
private Collection<Article> articles;
PublicAccount(String name) {
this.name = name;
subscribers = new ArrayList<>();
articles = new LinkedList<>();
};
@Override
public synchronized void addSubscriber(Observer observer) {
subscribers.add(observer);
}
@Override
public synchronized void removeSubscriber(Observer observer) {
subscribers.remove(observer);
}
@Override
public synchronized void publish(Article article) {
articles.add(article);
System.out.println(name + " is publishing new article...");
for (Observer subscriber : subscribers) {
subscriber.update(article);
}
}
}
public interface Observer<T> {
void update(T object);
}
public class ArticleFans implements Observer<Article> {
private String name;
ArticleFans(String name) {
this.name = name;
};
@Override
public void update(Article article) {
System.out.println(name + " got article「" + article.getName() + "」");
}
}
public class Article {
private String name;
private String content;
Article(String name, String content) {
this.name = name;
this. content = content;
};
public String getName() {
return name;
}
}
public class Test {
public static void main(String[] args) {
PublicAccount publicAccount = new PublicAccount("Jump x Switch");
ArticleFans link = new ArticleFans("Link");
ArticleFans mario = new ArticleFans("Mario");
publicAccount.addSubscriber(link);
publicAccount.addSubscriber(mario);
Article article = new Article("Pro Controller is on discount!", "……");
publicAccount.publish(article);
}
}
輸出:
Jump x Switch is publishing new article...
Link got article「Pro Controller is on discount!」
Mario got article「Pro Controller is on discount!」
我們關注了公衆號,其實就是把自己加入了公衆號的觀察者列表,當公衆號發佈新文章的時候,所有關注它的人,都會得到文章的推送。
JDK
中的java.util.Observable和java.util.Observer,是觀察者模式的簡單實現,不過現實中使用不多(在SWT
中應用很多)。
觀察者模式更多見於事件通知模型的框架中,如Netty
中隨處可見ChannelFuture和GenericFutureListener的組合;也可見於Redis
的Pub/Sub,ZooKeeper
的Watches……
4 總結
觀察者模式允許我們在對象狀態改變時得到通知,在一些高性能框架中得到了廣泛的應用,是異步編程的基礎。