觀察者模式學習
阿新 • • 發佈:2020-06-27
觀察者模式
1.基本介紹
- 物件之間多對一依賴的一種設計模式,依賴的物件為Subject,被依賴的物件為Observer,Subject通知Observer變化
2.原理類圖
- Subject為訊息傳送站,他的三個方法分別:
- registerObServer():訂閱,註冊第三方,需要接受訊息的物件
- removeObServe ():移除第三方
- notifyObServer():傳送通知,監聽到動態則傳達給訂閱的物件
- ObServer為各個第三方的物件
- update():被呼叫的方法,通過該方法給第三方觀察者傳遞訊息
3.案例
1.案例要求
- 使用觀察者模式實現一個多對一的案例:天氣訊息推送系統,向多個第三方網站推送天氣預報情況
2.實現類圖
-
WeatherData:天氣預報站,向觀察者(第三方網站Observer)傳送通知
- observers:通過註冊的第三方網站集合,即接受通知的物件集合
-
Observer:第三方介面,需要接受通知的物件實現該介面
3.程式碼實現
Subject介面
public interface Subject {
//註冊一個觀察者
void register(Observer observer);
//移除一個觀察者
void remove(Observer observer);
//發出通知
void notifyObserver();
}
核心類WeatherData
//包含最新的天氣情況訊息 //含有 觀察者集合,使用ArrayList管理 //當資料有更新時,就主動的呼叫 ArrayList他們(接入方)就看到最新的資訊 public class WeatherData implements Subject{ //天氣資訊 private Integer temperature; private Integer humidity; //觀察者集合 private ArrayList<Observer> observers; //構造器 public WeatherData() { // TODO Auto-generated constructor stub observers=new ArrayList<>(); temperature=0; humidity=0; } //註冊一個觀察者 @Override public void register(Observer observer) { // TODO Auto-generated method stub observers.add(observer); } //移除一個觀察者 @Override public void remove(Observer observer) { // TODO Auto-generated method stub observers.remove(observer); } //向觀察者發出通知 @Override public void notifyObserver() { // TODO Auto-generated method stub for(Observer observer : observers) { observer.update(temperature,humidity); } } //更新資料時發出通知 public void setData(Integer temperature,Integer humidity) { this.temperature=temperature; this.humidity = humidity; notifyObserver(); } }
觀察者介面:具體的第三方物件實現該介面的update方法,各自對獲取到的天氣資訊進行處理
public interface Observer {
void update(Integer temperature, Integer humidity);
}
觀察者實現:一個為例
public class Sina implements Observer{
//實現update獲取資料
@Override
public void update(Integer temperature, Integer humidity) {
//各自進行實現
display(temperature, humidity);
}
public void display(Integer temperature, Integer humidity) {
System.out.println("新浪提醒你,最新溫度:"+temperature);
System.out.println("新浪提醒你,最新溼度:"+humidity);
}
}
Client呼叫
public class Client {
public static void main(String[] args) {
//建立一個關鍵類,訊息傳送站
WeatherData weatherData = new WeatherData();
//建立觀察者類
Observer baidu = new Baidu();
Observer sina = new Sina();
//註冊觀察者
weatherData.register(baidu);
weatherData.register(sina);
//更新資料測試
weatherData.setData(30,20);
System.out.println("===========================");
//移除觀察者
weatherData.remove(baidu);
//更新資料測試
weatherData.setData(25, 39);
}
}
4.小結
- 使用觀察者模式能夠在符合ocp原則的前提下實現需求,當需要新增新的觀察者時,不需要對訊息站進行改動,通過直接向訊息站中的觀察者集合新增新的觀察者,以達到動態的控制多對一的依賴
4.JDK中的Observable原始碼分析
Observable充當了Subject的角色,即是介面也是實現,在這裡是個類,實現了所有核心方法
public class Observable {
private boolean changed = false;
//觀察者集合
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
//註冊一個觀察者(執行緒安全)
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
//刪除一個觀察者(執行緒安全)
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
//傳送通知
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
而觀察者介面,與我們定義的一致,擁有一個update方法
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}