1. 程式人生 > 實用技巧 >觀察者模式學習

觀察者模式學習

觀察者模式

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);
}