title: Day55-設計模式-觀察者模式
date: 2021-03-26 15:46:29
author: Liu_zimo
設計模式
- 設計模式分為三種類型,共23種
- 建立型模式:單例模式、抽象工廠模式、原型模式、建造者模式、工廠模式。
- 結構型模式:擴充卡模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式、代理模式。
- 行為型模式:模版方法模式、指令模式、通路者模式、疊代器模式、觀察者模式、中介者模式、備忘錄模式、解釋器模式(Interpreter模式)、狀态模式、政策模式、職責鍊模式(責任鍊模式)。
觀察者模式
- 天氣預報項目需求
- 氣象站可以将每天測量到的溫度,濕度,氣壓等等以公告的形式釋出出去(比如釋出到自己的網站或第三方)
- 需要設計開放型API,便于其他第三方也能接入氣象站擷取資料
- 提供溫度、氣壓和濕度的接口
- 測量資料更新時,要能實時的通知給第三方
- 普通方案
- 通過對氣象站項目的分析,我們可以初步設計出一個WeatherData類
- 通過getXxx方法,可以讓第三方接入,并得到相關資訊
- 當資料有更新時,氣象站通過調用dataChange()去更新資料,當第三方再次擷取時,就能得到最新資料,當然也可以推送。
- 問題分析:
- 其他第三方接入氣象站擷取資料的問題
- 無法在運作時動态的添加第三方(新浪網站)
- 違反ocp原則 => 觀察者模式
- 在WeatherData中,當增加一個第三方,都需要建立一個對應的第三方的公告闆對象,并加入到dataChange,不利于維護,也不是動态加入
package com.zimo.設計模式.行為型模式.觀察者模式.普通方案;
/**
* 設計模式 - 觀察者模式:天氣預報案例 - 普通方案
* 目前氣象情況
* @author Liu_zimo
* @version v0.1 by 2021/3/26 16:37
*/
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;
this.display();
}
public void display(){
System.out.println("--- today mT:" + this.temperature + "---");
System.out.println("--- today mP:" + this.pressure + "---");
System.out.println("--- today mH:" + this.humidity + "---");
}
}
----------------------------------------------------------------------------
package com.zimo.設計模式.行為型模式.觀察者模式.普通方案1;
/**
* 設計模式 - 觀察者模式:天氣預報案例 - 普通方案
* 氣象資料類 - 核心類
* 1.包含最新的天氣情況 2.含有CurrentConditions對象
* 3.當資料有更新時,就主動的調用CurrentConditions對象update方法(含display),這樣他們(接入方)就看到最新的資訊
* @author Liu_zimo
* @version v0.1 by 2021/3/26 16:10
*/
public class WeatherData {
private float temperature; // 溫度
private float pressure; // 氣壓
private float humidity; // 濕度
private CurrentConditions currentConditions;
public WeatherData(CurrentConditions currentConditions) { this.currentConditions = currentConditions; }
public float getTemperature() { return temperature; }
public float getPressure() { return pressure; }
public float getHumidity() { return humidity; }
public void dataChange(){ currentConditions.update(getTemperature(), getPressure(), getHumidity()); }
// 當資料更新時,調用setData
public void setData(float temperature, float pressure, float humidity){
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
// 将最新的資訊推送給接入方
dataChange();
}
}
----------------------------------------------------------------------------
public static void main(String[] args) {
// 建立一個接入方
CurrentConditions currentConditions = new CurrentConditions();
WeatherData weatherData = new WeatherData(currentConditions);
weatherData.setData(30, 150, 40);
System.out.println("天氣變更");
weatherData.setData(40, 160, 20);
}
觀察者模式原理
- 觀察者模式類似訂牛奶業務
- 牛奶站/氣象局:Subject
- 使用者/第三方網站:Observer
- Subject:登記注冊、移除和通知
- registerObserver 注冊
- removeObserver 移除
- notifyObservers()通知所有的注冊的使用者,根據不同需求,可以是更新資料,讓使用者來取,也可能是實施推送,看具體需求定
- Observer:接收輸入
-
觀察者模式:對象之間多對一依賴的一種設計方案,被依賴的對象為Subject,依賴的對象為Observer,Subject通知Observer變化,比如這裡的奶站是
Subject,是1的一方。使用者時Observer,是多的一方。
package com.zimo.設計模式.行為型模式.觀察者模式.天氣預報;
/**
* 設計模式 - 觀察者模式:天氣預報案例
* 觀察者接口
* @author Liu_zimo
* @version v0.1 by 2021/3/26 17:20
*/
public interface Observer {
public void update(float temperature,float pressure, float humidity);
}
--------------------------------------------------------------------------
package com.zimo.設計模式.行為型模式.觀察者模式.天氣預報;
/**
* 設計模式 - 觀察者模式:天氣預報案例
* 氣象站
* @author Liu_zimo
* @version v0.1 by 2021/3/26 17:17
*/
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
--------------------------------------------------------------------------
package com.zimo.設計模式.行為型模式.觀察者模式.天氣預報;
import com.zimo.設計模式.行為型模式.觀察者模式.普通方案.CurrentConditions;
import java.util.ArrayList;
/**
* 設計模式 - 觀察者模式:天氣預報
* 氣象資料類 - 核心類
* 1.包含最新的天氣情況 2.含有觀察者集合,使用ArrayList管理
* 3.當資料有更新時,就主動的調用ArrayList,通知所有的(接入方)看到最新的資訊
* @author Liu_zimo
* @version v0.1 by 2021/3/26 17:24
*/
public class WeatherData implements Subject{
private float temperature; // 溫度
private float pressure; // 氣壓
private float humidity; // 濕度
private ArrayList<Observer> observers;
public WeatherData() { this.observers = new ArrayList<>(); }
public void dataChange(){ notifyObservers(); }
// 當資料更新時,調用setData
public void setData(float temperature, float pressure, float humidity){
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
// 将最新的資訊推送給接入方
dataChange();
}
@Override // 注冊一個觀察者
public void registerObserver(Observer o) { observers.add(o); }
@Override // 移除一個觀察者
public void removeObserver(Observer o) { if (observers.contains(o)) observers.remove(o); }
@Override
public void notifyObservers() {
for (Observer observer : this.observers) {
observer.update(this.temperature, this.pressure, this.humidity);
}
}
}
--------------------------------------------------------------------------
package com.zimo.設計模式.行為型模式.觀察者模式.天氣預報;
/**
* 設計模式 - 觀察者模式:天氣預報
* 目前氣象情況
* @author Liu_zimo
* @version v0.1 by 2021/3/26 17:23
*/
public class CurrentConditions 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;
this.display();
}
public void display(){
System.out.println("--- today mT:" + this.temperature + "---");
System.out.println("--- today mP:" + this.pressure + "---");
System.out.println("--- today mH:" + this.humidity + "---");
}
}
--------------------------------------------------------------------------
package com.zimo.設計模式.行為型模式.觀察者模式.天氣預報;
/**
* 設計模式 - 觀察者模式:天氣預報
* 百度接入
* @author Liu_zimo
* @version v0.1 by 2021/3/26 17:37
*/
public class BaiduSite implements Observer{
private float temperature; // 溫度
private float pressure; // 氣壓
private float humidity; // 濕度
public void update(float temperature, float pressure, float humidity){
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
this.display();
}
public void display(){
System.out.println("--- baidu mT:" + this.temperature + "---");
System.out.println("--- baidu mP:" + this.pressure + "---");
System.out.println("--- baidu mH:" + this.humidity + "---");
}
}
--------------------------------------------------------------------------
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditions currentConditions = new CurrentConditions();
BaiduSite baiduSite = new BaiduSite();
weatherData.registerObserver(currentConditions);
weatherData.registerObserver(baiduSite);
weatherData.setData(10, 100, 30);
weatherData.removeObserver(currentConditions);
weatherData.setData(30, 200, 20);
}
- 觀察者模式的好處:
- 觀察者模式設計後,會以集合的方式來管理使用者(Observer),包括注冊,移除和通知
- 這樣,我們增加觀察者(這裡可以了解成一個新的公告闆),就不需要去修改核心類WeatherData不會修改代碼,遵守了ocp原則
JDK中應用源碼分析
- JDK的Observable類就使用了觀察者模式
- Observable的作用和地位 ===>>> Subject
- Observable是類,不是接口,類中已經實作了核心的方法,即管理Observer的方法add… delete… notify…
- Observer的作用和地位 ===>>> Observer,有update
- Observable和 Observer的使用方法和前面講過的一樣,隻是Observable是類,通過繼承來說實作觀察者模式