觀察者屬於行爲型模式的一種, 又叫發佈-訂閱模式. 若是一個對象的狀態發生改變,依賴他的對象都將發生變化, 那麼這種狀況就適合使用觀察者模式.html
它包含兩個術語,主題(Subject),觀察者(Observer), 主題管理一個觀察者的列表, 並在狀態發生變化時通知到他們.java
實現層面上, 主題定義了一個觀察者列表並能夠管理這個列表(將觀察者註冊進去和撤銷註冊的行爲), 同時定義了通知到全部觀察者的行爲.api
Java類庫有默認的觀察者實現類Observer. 使用觀察者模式的還有事件監聽, RxJava等.多線程
定義對象之間的一對多依賴,當一個對象狀態改變時,它的全部依賴都會收到通知而且自動更新狀態。oracle
一. 定義抽象觀察者異步
/** * 觀察者抽象角色 */ public interface MyObserver { void update(Subject subject); }
二. 定義抽象主題this
/** * 主題抽象角色 */ public abstract class Subject { private ArrayList<MyObserver> list = new ArrayList<MyObserver>(); public Subject register(MyObserver observer){ if(!list.contains(observer)){ list.add(observer); } return this; } public Subject unRegister(MyObserver observer){ if(list.contains(observer)){ list.remove(observer); } return this; } public final void notifyObservers(){ for (MyObserver item:list) { item.update(this); } } /** * 具體狀態的變動 */ abstract void change(); }
三. 定義具體主題spa
/** * 具體主題角色 */ @Data public class ConcreteSubject extends Subject { private String name; public void change() { this.setName("王多魚"); super.notifyObservers(); } }
四. 定義觀察者的實現, 分別定義兩個不一樣實現線程
public class UncleObserver implements MyObserver { public void update(Subject subject) { ConcreteSubject concreteSubject = (ConcreteSubject)subject; System.out.println("UncleObserver 知道了: "+concreteSubject.getName()); } } public class HentaiObserver implements MyObserver { public void update(Subject subject) { ConcreteSubject concreteSubject = (ConcreteSubject)subject; System.out.println("HentaiObserver 知道了: "+concreteSubject.getName()); } }
五. 調用, 首先註冊觀察者,而後調用主題的變動方法code
// 實例化主題後爲其註冊了兩個觀察者的實例, 並最終調用主題的變動方法觸發通知行爲 public static void main(String[] args) { new ConcreteSubject() .register(new UncleObserver()) .register(new HentaiObserver()) .change(); }
關鍵點: 定義通知到觀察者的方法要注意, 若是有耗時嚴重的會阻塞其餘觀察者獲得通知, 能夠異步多線程實現; 避免循環引用;
觀察者分推模式和拉模式, 推模式是指將主題的變動信息發送給觀察者, 觀察者能夠用, 也能夠不用. 拉模式則是將主題的引用發送給觀察者, 觀察者經過引用根據本身須要獲取所需信息. 示例中使用的就是這種模式.
代碼修改成推模式
// 觀察者的方法接收具體信息 void update(String name); // 主題的通知方法作相應修改 public final void notifyObservers(){ for (MyObserver item:list) { item.update("王多魚"); } }