定義
定義對象的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。
觀察者模式是行爲型模式之一。包含觀察者模式包括觀察者與被觀察者兩個基本元素,觀察者會註冊到被觀察者中,而被觀察者會保持和觀察者的對應關係。
如果被觀察的對象產生一些觀察者感興趣的變更,則觀察者會得到通知從而去執行相關的操作。
常見的觀察者模式
提到觀察者模式,首先會想到前端中常用的事件機制。例如爲dom元素綁定事件:
$(document).click(function (e) {
console.dir(e);
});
這裏的匿名function就是觀察者,而document則是被觀察者,.click(function)則是觀察者註冊的過程,此後document發生click事件時,被觀察者則會收到通知,從而執行自己的邏輯console.dir(e)。
使用觀察者模式
現在我們使用Java來模擬觀察者模式。
先創建事件,包含事件源,通知目標,回調方法以及觸發者等屬性。
/**
* 事件
*/
public class Event {
private Object source; // 事件源
private Object target; // 通知目標
private Method callback; // 回調方法名稱
private String trigger; // 觸發者
private long time;
public Event(Object target, Method callback) {
this.target = target;
this.callback = callback;
}
// 省略getter、setter
}
定義事件類型,此處定義添加、刪除兩種類型。
/**
* 事件類型
*/
public enum EventType {
/**
* 添加
*/
ADD,
/**
* 刪除
*/
RMOVE
}
定義抽象被觀察者(主題),包含主題名稱,保持與觀察者引用映射的容器,以及事件觸發的方法。
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* 抽象主題
* 定義主題通用的容器、事件註冊及事件觸發
*/
public class AbstractSubject {
protected String name;
protected Map<Enum,Event> eventMap = new HashMap<>(); // 註冊容器
public AbstractSubject() {}
protected AbstractSubject(String name) {
this.name = name;
}
/**
* 事件註冊
* @param eventType
* @param target
* @param callback
*/
public void addLisenter(Enum eventType, Object target, Method callback) {
eventMap.put(eventType, new Event(target, callback));
}
/**
* 事件觸發
* @param eventType
*/
protected void trigger(Enum eventType) {
Event event = this.eventMap.get(eventType);
if(null == event) {
return;
}
event.setSource(this);
event.setTrigger(eventType.toString());
event.setTime(System.currentTimeMillis());
try {
event.getCallback().invoke(event.getTarget(), event);
} catch (Exception e1) {
e1.printStackTrace();
}
}
// 省略getter、setter
}
定義具體主題:
/**
* 主題,被觀察者
*/
public class Subject extends AbstractSubject {
public Subject(String name) {
super.name = name;
}
public void add() {
trigger(EventType.ADD);
}
public void remove() {
trigger(EventType.RMOVE);
}
}
定義觀察者,包含添加、刪除事件對應的回調方法。
/**
* 觀察者
*/
public class Observer {
public void onAdd(Event event) {
System.out.println("收到" + event.getTrigger() + "的添加事件");
}
public void onRemove(Event event) {
System.out.println("收到" + event.getTrigger() + "的刪除事件");
}
}
測試類:
/**
* 測試類
*/
public class Test {
public static void main(String[] args) throws NoSuchMethodException {
// 觀察者
Observer observer = new Observer();
// 觀察者收到通知後執行的方法
Method onAdd = Observer.class.getMethod("onAdd", Event.class);
Method onRemove = Observer.class.getMethod("onRemove", Event.class);
// 被觀察者
Subject subject = new Subject("目標1號");
// 事件綁定
subject.addLisenter(EventType.ADD, observer, onAdd);
subject.addLisenter(EventType.RMOVE, observer, onRemove);
// 被觀察者觸發事件
subject.add();
subject.remove();
}
}
其中,得到觀察者和主題對象後,進行觀察者的註冊,然後主題執行動作觸發事件,這是整個流程。
如果需要做成主題和觀察者一對多的映射,則將Event的target改成集合類型,如下:
private List<Object> targets; // 通知目標