觀察者模式
傳統方法:
/**
* @author 孫一鳴 on 2020/2/18
*
* 包含最新的天氣信息
*/
public class WeatherData {
private float temperatrue;
private float pressure;
private float humidity;
private CurrentConditions currentConditions;
public WeatherData(CurrentConditions currentConditions) {
this.currentConditions = currentConditions;
}
public float getTemperature() {
return temperatrue;
}
public float getPressure() {
return pressure;
}
public float getHumidity() {
return humidity;
}
public void dataChange() {
//數據改變時,調用第三方的方法,通知第三方
currentConditions.update(getTemperature(), getPressure(), getHumidity());
}
//數據更新
public void setData(float temperature, float pressure, float humidity) {
this.temperatrue = temperature;
this.pressure = pressure;
this.humidity = humidity;
dataChange();
}
}
第三方使用數據網站
/**
* @author 孫一鳴 on 2020/2/18
*/
public class CurrentConditions {
//溫度 氣壓 溼度
private float temperature;
private float pressure;
private float humidity;
//每次數據更新 數據WeatherData 將調用此方法 ,並將最新數據傳入
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("***Today mTemperature: " + temperature + "***");
System.out.println("***Today mPressure: " + pressure + "***");
System.out.println("***Today mHumidity: " + humidity + "***");
}
}
測試:
/**
* @author 孫一鳴 on 2020/2/18
*/
public class Client {
public static void main(String[] args) {
CurrentConditions currentConditions = new CurrentConditions();
WeatherData weatherData = new WeatherData(currentConditions);
weatherData.setData(30, 150, 40);
}
}
分析:
如果此時,百度網站也想要獲得天氣數據,我們該怎麼改呢?
1.創建觀察數據者 百度網站
2.更改目標數據WeatherData
違反ocp原則,
//在WeatherData中,當增加一個第三方,都需要創建一個對應的第三方的公告板對象,並加入到dataChange, 不利於維護,也不是動態加入
public void dataChange() {
currentConditions.update(getTemperature(), getPressure(), getHumidity());
}
觀察者模式:
觀察者模式類似訂牛奶業務
- 奶站/氣象局:Subject
- 用戶/第三方網站:Observer
Subject:登記註冊、移除和通知
1) registerObserver 註冊
2) removeObserver 移除
3) notifyObservers() 通知所有的註冊的用戶,根據不同需求,可以是更新數據,讓用戶來取,也可能是實施推送,看具體需求定
Observer:接收輸入
update()
觀察者模式:對象之間多對一依賴的一種設計方案,被依賴的對象爲Subject,依賴的對象爲Observer,Subject通知Observer變化,比如這裏的奶站是Subject,是1的一方。用戶時Observer,是多的一方。
類圖:
觀察者模式結構中通常包括觀察目標和觀察者兩個繼承層次結構
目標: Subject 接口:
/**
* @author 孫一鳴 on 2020/2/18
* 接口,讓WeatherData 來實現
*/
public interface Subject {
public void registerObserver(MyObserver o);
public void removeObserver(MyObserver o);
public void notifyObserver();
}
觀察者: Observer 接口:
/**
* 觀察者接口
* @author 孫一鳴 on 2020/2/18
*/
public interface MyObserver {
public void update(float temperature , float pressure ,float humidity);
}
觀察者: Observer 實現 : 百度網站要獲得天氣信心 :
/**
* @author 孫一鳴 on 2020/2/18
*/
public class BaiDuCurrentConditions implements Observer {
//溫度 氣壓 溼度
private float temperature;
private float pressure;
private float humidity;
//每次數據更新 數據WeatherData 將調用此方法 ,並將最新數據傳入
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("***Today mTemperature: " + temperature + "***");
System.out.println("***Today mPressure: " + pressure + "***");
System.out.println("***Today mHumidity: " + humidity + "***");
}
}
目標: subject實現 : 氣象中心發佈信息:
/**
* @author 孫一鳴 on 2020/2/18
* <p>
* 包含最新的天氣信息
* 使用ArrayList 管理觀察者
* 當數據更新時 主動遍歷ArrayList 通知觀察者 更改最新信息
*/
public class WeatherData implements Subject {
private float temperature;
private float pressure;
private float humidity;
//private CurrentConditions currentConditions;
//觀察者集合
private ArrayList<MyObserver> observers;
public WeatherData() {
observers = new ArrayList<>();
}
public float getTemperature() {
return temperature;
}
public float getPressure() {
return pressure;
}
public float getHumidity() {
return humidity;
}
public void dataChange() {
notifyObserver();
}
//數據更新
public void setData(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
dataChange();
}
@Override
public void registerObserver(MyObserver o) {
observers.add(o);
}
@Override
public void removeObserver(MyObserver o) {
observers.remove(o);
}
@Override
public void notifyObserver() {
for (int i = 0; i <observers.size() ; i++) {
observers.get(i).update(this.temperature,this.pressure,this.humidity);
}
}
}
觀察者模式測試:
/**
* @author 孫一鳴 on 2020/2/18
*/
public class Client {
public static void main(String[] args) {
//創建目標
WeatherData weatherData = new WeatherData();
//創建觀察者
CurrentConditions currentConditions = new CurrentConditions();
//註冊觀察者
weatherData.registerObserver(currentConditions);
//測試
weatherData.setData(100, 100, 40);
}
}
觀察者模式的好處
- 觀察者模式設計後,會以集合的方式來管理用戶(Observer),包括註冊,移除
和通知。 - 這樣,我們增加觀察者(這裏可以理解成一個新的公告板),就不需要去修改核
心類WeatherData不會修改代碼,遵守了ocp原則。