十一大行為型模式之七:觀察者模式。
簡介
姓名 :觀察者模式
英文名 :Observer Pattern
價值觀 :盯著你怎麼著
個人介紹 :
Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically. 定義物件間一種一對多的依賴關係,使得每當一個物件改變狀態,則所有依賴於它的物件都會得到通知並被自動更新。 (來自《設計模式之禪》)
你要的故事
想來想去,就拿我們現在生活中最常體會到的事情來講觀察者模式--朋友圈。小明、小紅、小東 3 人是好朋友,最近他們的父母都給安排了手機,剛用上手機那是相當的興奮呀。他們立馬從 QQ 轉投到微信的懷抱,對微信的朋友圈玩的不亦樂乎,什麼事情都往上面發。突然有一天,小明和小紅因為一些小事爭執鬧彆扭了,原因就是他們對一道數學題有不同的見解。就跟我們小時候和朋友玩得好好的,突然因為一點小事就鬧翻了。小紅比較孩子氣,立馬就遮蔽了小明的朋友圈,不想再看到有關小明相關的資訊。故事就是這麼一回事,關注點就在這朋友圈
上。朋友圈就是運用觀察者模式的一個很好的樣例。為什麼這麼說?我們發朋友圈的時候,那些沒有遮蔽我們朋友圈的好友,會收到資訊推送。也就是沒有遮蔽我們朋友圈的好友其實是訂閱了我們朋友圈,好友相當於觀察者,我們是被觀察的物件。符合觀察者模式這個關係。
我們通過程式碼來描述小明、小紅、小東他們在朋友圈玩的場景。利用觀察者模式,需要觀察物件和被觀察物件,所以我們先定義 2 個介面,分別是 Observable
(可被觀察介面) 和 Observer
(觀察者介面)。
實現 Observable
介面的物件說明是可被訂閱觀察的,所以它需要 addObserver()
新增訂閱者方法和 removeObserver()
移除訂閱者方法,另外還有一個是必須的,就是通知各個訂閱者訊息的方法 notifyObservers()
。那 Observable
介面程式碼如下所示。
interface Observable {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String message);
}
複製程式碼
實現 Observer
介面的物件說明是可以去訂閱觀察的,也就是說可以接收被訂閱的物件發出來的訊息,那就需要一個接收訊息的方法 update()
。程式碼如下所示。
interface Observer {
void update(String name, String message);
}
複製程式碼
為了讓大家不混淆,先把觀察者和被觀察者分離開,其實在這個例子中,觀察者和被觀察者是同一個物件 User
的。這裡就分開,分成 User
和 Friend
,後面會給出正確的程式碼,稍安勿躁哈。這裡 User
作為被觀察者,實現了 Observable
介面,而 Friend
作為觀察者,實現了 Observer
介面。程式碼如下。
class User implements Observable {
private List<Observer> friends;
private String name;
public User(String name) {
this.name = name;
this.friends = new LinkedList<>();
}
public void sendMessage(String message) {
this.notifyObservers(message);
}
@Override
public void addObserver(Observer observer) {
this.friends.add(observer);
}
@Override
public void removeObserver(Observer observer) {
this.friends.remove(observer);
}
@Override
public void notifyObservers(String message) {
this.friends.forEach(friend -> {
friend.update(this.name, message);
});
}
}
class Friend implements Observer {
private String name;
public Friend(String name) {
this.name = name;
}
@Override
public void update(String name, String message) {
System.out.println("【" + this.name + "】看到【" + name + "】發的朋友圈:" + message);
}
}
public class ObserverTest {
public static void main(String[] args) {
User xiaoMing = new User("小明");
Friend xiaoHong = new Friend("小紅");
Friend xiaoDong = new Friend("小東");
xiaoMing.addObserver(xiaoHong);
xiaoMing.addObserver(xiaoDong);
xiaoMing.sendMessage("今天真開心");
// 小紅和小明鬧彆扭了,小紅取消訂閱小明的朋友圈
xiaoMing.removeObserver(xiaoHong);
xiaoMing.sendMessage("希望明天也像今天一樣開心");
}
}
列印結果:
【小紅】看到【小明】發的朋友圈:今天真開心
【小東】看到【小明】發的朋友圈:今天真開心
【小東】看到【小明】發的朋友圈:希望明天也像今天一樣開心
複製程式碼
看到程式碼執行結果,小紅和小東都訂閱了小明的朋友圈,小明發了朋友圈:今天真開心。他們倆都收到了,因為小紅和小明鬧彆扭,小紅取消訂閱小明的朋友圈,所以小明後來發的朋友圈,小紅沒收到。
上面程式碼其實是不對的,不應該用 User
和 Friend
2 個類來定義。如果小明訂閱小紅和小東的朋友圈呢?這樣實現比較麻煩,主要是為了分清 觀察者
和 被觀察者
這 2 個概念,通過上面的例子應該分清楚了 2 個概念了,那就可以來看正確的程式碼,小明、小紅、小東他們其實都是觀察者和被觀察者,所以我們用 User2
來定義他們就可以,User2
實現了 Observable
和 Observer
介面。程式碼如下。
class User2 implements Observable, Observer {
private List<Observer> friends;
private String name;
public User2(String name) {
this.name = name;
this.friends = new LinkedList<>();
}
@Override
public void addObserver(Observer observer) {
this.friends.add(observer);
}
@Override
public void removeObserver(Observer observer) {
this.friends.remove(observer);
}
@Override
public void notifyObservers(String message) {
this.friends.forEach(friend -> {
friend.update(this.name, message);
});
}
@Override
public void update(String name, String message) {
System.out.println("【" + this.name + "】看到【" + name + "】發的朋友圈:" + message);
}
public void sendMessage(String message) {
this.notifyObservers(message);
}
}
public class ObserverTest {
public static void main(String[] args) {
User2 xiaoMing2 = new User2("小明");
User2 xiaoHong2 = new User2("小紅");
User2 xiaoDong2 = new User2("小東");
xiaoMing2.addObserver(xiaoHong2);
xiaoMing2.addObserver(xiaoDong2);
xiaoMing2.sendMessage("今天真開心");
xiaoMing2.removeObserver(xiaoHong);
xiaoMing2.sendMessage("希望明天也像今天一樣開心");
xiaoHong2.addObserver(xiaoMing2);
xiaoHong2.addObserver(xiaoDong2);
xiaoHong2.sendMessage("今天和小明吵架了,遮蔽他的朋友圈");
xiaoDong2.addObserver(xiaoMing2);
xiaoDong2.addObserver(xiaoHong2);
xiaoDong2.sendMessage("小明和小紅吵架了,夾在中間好尷尬");
}
}
列印結果:
【小紅】看到【小明】發的朋友圈:今天真開心
【小東】看到【小明】發的朋友圈:今天真開心
【小紅】看到【小明】發的朋友圈:希望明天也像今天一樣開心
【小東】看到【小明】發的朋友圈:希望明天也像今天一樣開心
【小明】看到【小紅】發的朋友圈:今天和小明吵架了,遮蔽他的朋友圈
【小東】看到【小紅】發的朋友圈:今天和小明吵架了,遮蔽他的朋友圈
【小明】看到【小東】發的朋友圈:小明和小紅吵架了,夾在中間好尷尬
【小紅】看到【小東】發的朋友圈:小明和小紅吵架了,夾在中間好尷尬
複製程式碼
從程式碼中,我們看到小明、小紅、小東 3 個人互相訂閱朋友圈,當然中途小紅遮蔽了小明的朋友圈。這就是 觀察者
和 被觀察者
剛好是同一個物件的實現。
總結
觀察者模式
是一個比較特殊的設計模式,它定義了觸發機制,觀察者只要訂閱了被觀察者,就可以第一時間得到被觀察者傳遞的資訊。在工作中,使用觀察者模式的場景也比較多,比如訊息佇列消費,Android 開發中的事件觸發機制等等。好,觀察者模式就到這。
推薦閱讀:
設計模式系列文章持續更新中,歡迎關注公眾號 LieBrother,一起交流學習。