觀察者模式(Observer Pattern)
定義
- 觀察者模式定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知所有觀察者對象,使它們能夠自動更新自己。
- 別名:模型-視圖模式、源-收聽者模式、從屬者模式、發布-訂閱模式。
- 觀察者模式通過解耦觀察者和被觀察者,使得它們可以獨立地變化和復用。
- 是行為型設計模式。
適用場景
- 當一個抽象模型包含兩個方面內容,其中一個方面依賴于另一個方面;
- 其他一個或多個對象的變化依賴于另一個對象的變化;
- 實現類似于廣播機制的功能,無需知道具體收聽者,只需分發廣播,系統中感興趣的對象會自動接收該廣播;
- 多層級嵌套使用,形成一種鏈式觸發機制,使得事件具備跨域(跨越兩種觀察者類型)通知。
標準示例
觀察者模式通常包含以下幾個角色:
Subject(主題/被觀察者):維護一個觀察者列表,并提供注冊、移除和通知觀察者的方法。
Observer(觀察者):定義一個更新接口,以便在得到主題通知時更新自己。
ConcreteSubject(具體主題):具體的被觀察者,在內部狀態改變時,通知所有注冊的觀察者。
ConcreteObserver(具體觀察者):實現抽象觀察者的定義,以便在得到主題狀態更改通知時更新自身。
示例代碼:
ISubject
抽象主題
/*** 抽象主題*/
public interface ISubject<E> {boolean attach(IObserver<E> observer);boolean detach(IObserver<E> observer);void notify(E event);
}
IObserver
抽象觀察者
/*** 抽象觀察者*/
public interface IObserver<E> {/*** 更新* @param event*/void update(E event);
}
ConcreteSubject
具體主題
/*** 具體主題*/
public class ConcreteSubject<E> implements ISubject<E>{private List<IObserver<E>> observers = new ArrayList<IObserver<E>>();public boolean attach(IObserver<E> observer) {return !this.observers.contains(observer) && this.observers.add(observer);}public boolean detach(IObserver<E> observer) {return this.observers.remove(observer);}public void notify(E event) {for(IObserver<E> observer:observers){observer.update(event);}}
}
ConcreteObserver
具體觀察者
public class ConcreteObserver<E> implements IObserver<E>{public void update(E event) {System.out.println(this.getClass().getSimpleName() + " receive event : " + event);}
}
客戶端調用代碼:
public class ClientTest {public static void main(String[] args) {//被觀察者ISubject<String> subject = new ConcreteSubject<String>();//觀察者IObserver<String> observer = new ConcreteObserver<String>();//被觀察者注冊subject.attach(observer);//通知subject.notify("hello");}
}
輸出執行結果:
ConcreteObserver receive event : hello
接下來,我們使用jdk中提供的觀察者模式接口來實現一個如下場景:
明星發聲,粉絲關注并收聽。
Idol
明星主題抽象類
/*** 抽象主題者——偶像*/
public interface Idol {void posting(String message);
}
ConcreteIdol
明星主題具體類
/*** 具體偶像類*/
@Data
public class ConcreateIdol extends Observable implements Idol{private String name;public ConcreateIdol(String name){this.name = name;}public void posting(String message) {System.out.println("【明星發布】 "+message);setChanged();notifyObservers(message);}
}
Fans
粉絲具體類
/*** 觀察者*/
public class Fans implements Observer {private String idol;private String selfName;public Fans(String idol,String selfName){this.idol = idol;this.selfName = selfName;}public void update(Observable o, Object arg) {System.out.println("【粉絲"+this.selfName+"收到通知】 " + "收到偶像消息:"+ arg);}
}
JDK中,java.util.Observable 類,相當于IObserver的存在,所以,我們的Fans類,只要繼承Observable即可。在發布的被監聽方法中,只要調用如下兩個方法,可以實現發布。
setChanged();
notifyObservers();
而監聽者實現類 Fans,只需要實現jdk中的 java.util.Observer 接口。其中的 update 方法,即為訂閱到發布消息后的回調方法。
ClientTest
客戶端調用類:
public class ClientTest {public static void main(String[] args) {ConcreateIdol zhazhahui = new ConcreateIdol("渣渣輝");zhazhahui.addObserver(new Fans(zhazhahui.getName(),"小明明"));zhazhahui.addObserver(new Fans(zhazhahui.getName(),"小甜甜"));String message = "大家好,我是"+zhazhahui.getName()+",歡迎體驗我代言的新版砍怪看到手抽筋大型即使PK古裝仙俠網游!";zhazhahui.posting(message);}
}
執行后的結果輸出為:
【明星發布】 大家好,我是渣渣輝,歡迎體驗我代言的新版砍怪看到手抽筋大型即使PK古裝仙俠網游!
【粉絲小甜甜收到通知】 收到偶像消息:大家好,我是渣渣輝,歡迎體驗我代言的新版砍怪看到手抽筋大型即使PK古裝仙俠網游!
【粉絲小明明收到通知】 收到偶像消息:大家好,我是渣渣輝,歡迎體驗我代言的新版砍怪看到手抽筋大型即使PK古裝仙俠網游!