基本介紹
觀察者模式(Observer Pattern)又被稱為釋出-訂閱(Publish/Subscribe)模式、模型-檢視(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式,屬於行為型模式的一種。
定義了一種一對多的模式,多個觀察者監視一個主題,當主題狀態發生變化時,會通知所有觀察者。觀察者之間沒有互相聯絡,可以增加、刪除觀察者,易於管理和擴充套件。
模式結構
Subject(抽象主題):和觀察者是一對多的關係,即一個主題可以繫結多個觀察者
ConcreteSubject(具體主題):實現抽象主題的方法,當主題內部發生變化時,通知所有繫結的觀察者
Observer(抽象觀察者):定義了更新的方法,當主題有變化時,通過此方法更新自己
ConcreteObserver(具體觀察者):實現抽象觀察者,實現更新方法
舉例說明
以使用者和頻道為例,當頻道有新的訊息時,會將通知傳送給所有訂閱了該頻道的使用者
1、抽象觀察者,定義了一個更新的方法
public interface Observer {
void update(String message);
}
2、具體觀察者:使用者,定義一個名稱屬性,實現抽象觀察者的方法
public class UserObserver implements Observer {
private String name;
public UserObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + "收到通知:" + message);
}
}
3、抽象主題,有新增、刪除、通知功能
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notify(String message);
}
4、具體主題:新聞頻道,定義一個 List 儲存觀察者,通知時迴圈遍歷集合進行通知
public class NewsSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void attach(Observer observer) {
observers.add(observer);
}
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
@Override
public void notify(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
5、測試類
public class Client {
@Test
public void test() {
Subject newsSubject = new NewsSubject();
Observer user1 = new UserObserver("小龍");
Observer user2 = new UserObserver("小鳳");
newsSubject.attach(user1);
newsSubject.attach(user2);
newsSubject.notify("新聞頻道釋出了一條緊急新聞");
}
}
6、執行結果
小龍收到通知:新聞頻道釋出了一條緊急新聞
小鳳收到通知:新聞頻道釋出了一條緊急新聞
7、如果我們需要新增其它頻道也非常的方便,只需要新增一個具體主題(比如體育頻道),其它業務程式碼無需改動,測試類中將使用者註冊進去即可。
模式分析
優點
- 耦合性低,讓耦合的雙方都依賴於抽象,當發生變化時,雙方互不干擾
- 擴充套件性高,新增具體主題或是新增具體觀察者,都無需修改其他程式碼
缺點
- 如果一個主題有很多直接或間接的觀察者,則通知的過程會花費很多時間
- 如果主題和觀察者之間有迴圈依賴,可能會造成程式死迴圈導致系統崩潰
適用場景
- 觀察者模式在軟體開發中應用非常廣泛,比如電商系統可以在執行傳送操作後給使用者多個傳送商品打折資訊,遊戲中隊友犧牲將給所有成員提示等等,凡是涉及到一對一或者一對多的物件互動場景都可以使用觀察者模式。