iT邦幫忙

2023 iThome 鐵人賽

DAY 6
0
自我挑戰組

深入淺出設計模式 (Head First Design Pattern) - 重點整理及範例分享系列 第 6

[深入淺出設計模式] Ch2 The Observer Pattern (3) - 【觀察者模式】範例 天氣監測系統 Weather Monitoring application

  • 分享至 

  • xImage
  •  

上一篇講解完天氣監測系統的大致架構,接下來看一下程式碼的部分~
(完整程式碼點我

首先是觀察者的介面,可以更新天氣資訊。

public interface Observer{
    public void update(float temp, float humidity, float pressure);
}

主體的介面,會包含註冊、移除、通知訂閱者的方法。

public interface Subject{
    public void registerObservers(Observer obr);
    public void removeObservers(Observer obr);
    public void notifyObservers(); 
}

用天氣資訊類別去實作主題介面,ArrayList<Observer> observers 是紀錄主題有哪些訂閱者的陣列,
透過陣列的新增移除來實現註冊和移除訂閱者的方法。天氣資料更改會使用 setMeasurements(),接著會呼叫measurementsChanged(),它會再呼叫 notifyObservers() 去實際更新天氣資訊讓每個訂閱者知道。

public class WeatherData implements Subject{
    private ArrayList<Observer> observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData(){
        observers = new ArrayList<Observer>();
    }

    public void registerObservers(Observer obr){
        observers.add(obr);    
    }

    public void removeObservers(Observer obr){
        int id = observers.indexOf(obr);
        if(id >= 1){
            observers.remove(id);
        }
    }

    public void notifyObservers(){
        for(int i = 0; i < observers.size(); i++){
            Observer obr = (Observer)observers.get(i);
            obr.update(temperature, humidity, pressure);
        }
    }

    public void measurementsChanged(){
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
}

顯示裝置的介面 DisplayElement()

public interface DisplayElement{
    public void display();
}

系統包含三種顯示模式,顯示模式會實作訂閱者以及顯示裝置的介面。

首先是最新資料顯示模式 CurrentConditionDisplay(),當 WeatherData 呼叫 notifyObservers() 時,WeatherData 透過迴圈以 update() 一一通知訂閱者資料已經更新,再用 display() 展示。

public class CurrentConditionDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Subject weatherData;

    public CurrentConditionDisplay(Subject weatherData){
        this.weatherData = weatherData;
        weatherData.registerObservers(this);
    }

    public void update(float temperature, float humidity, float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }

    public void display(){
        System.out.println("Current conditions: " + temperature + " degree / Humidity:" + humidity );
    }    
}

第二種為天氣預報模式 ForecastDisplay()

public class ForecastDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Subject weatherData;

    public ForecastDisplay(Subject weatherData){
        this.weatherData = weatherData;
        weatherData.registerObservers(this);
    }

    public void update(float temperature, float humidity, float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }

    public void display(){
        System.out.println("Tomorrow Weather : " + temperature + " degree / Humidity:" + humidity );
    }    
}

第三種是天氣資料統計模式,用來計算平均溫度、最高溫、最低溫,每次資料更新後,就會用tempSum加總之前的資料,重新再計算一次正確的數值。

    public class StatisticDisplay implements Observer, DisplayElement {
	private float maxTemp = 0.0f;
	private float minTemp = 200;
	private float tempSum= 0.0f;
	private int numReadings;
	private WeatherData weatherData;

	public StatisticDisplay(WeatherData weatherData) {
		this.weatherData = weatherData;
		weatherData.registerObservers(this);
	}

	public void update(float temp, float humidity, float pressure) {
		tempSum += temp;
		numReadings++;

		if (temp > maxTemp) {
			maxTemp = temp;
		}
 
		if (temp < minTemp) {
			minTemp = temp;
		}

		display();
	}

	public void display() {
		System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings)
			+ "/" + maxTemp + "/" + minTemp);
	}
}

來實際跑一次,手動模擬新的天氣資料被寫入

public class WeatherStation{
    public static void main(String[] string){
        WeatherData curData = new WeatherData();   
        CurrentConditionDisplay c = new CurrentConditionDisplay(curData);
        StatisticDisplay s = new StatisticDisplay(curData);

        curData.setMeasurements(32,65,30.4f);
        curData.setMeasurements(30, 92, 20.4f);

        WeatherData forecastData = new WeatherData();
        ForecastDisplay f = new ForecastDisplay(forecastData);
        forecastData.setMeasurements(27,74,45f);
        
        curData.setMeasurements(34, 55, 32.9f);
    }
}

最後輸出:
https://ithelp.ithome.com.tw/upload/images/20230921/201631781qLfzsfQJn.png

小碎念( •́ὤ•̀)
本來以為統計資料也要包含濕度、氣壓,害我超苦惱要怎麼寫,結果到書中附的程式碼一看發現是個簡單粗暴的答案⋯⋯
第一次參加這種活動,發現寫文章比我想的難好多,所以我超謹慎地一直查資料,很怕寫錯會誤導別人(瘋掉)
雖然整體應該看得出來我很菜,不過這樣的確讓我對這些東西印象深刻哈哈哈


參考資料:

  1. 《深入淺出設計模式 (Head First Design Patterns) 》
  2. 書中程式碼傳送門

程式碼

https://github.com/changtintin/Design-Pattern/tree/master/Ch2/Java


Disclaimer
因為讀的是原文版,所以難免會有翻譯詞不達意或是專有名詞上的差異,有錯誤的話歡迎在留言區一起交流!


上一篇
[深入淺出設計模式] Ch2 The Observer Pattern (2) - 【觀察者模式】範例 天氣監測系統 Weather Monitoring application
下一篇
[深入淺出設計模式] Ch2 The Observer Pattern (4) - 【觀察者模式】範例 Life-changing application 改變命運的應用
系列文
深入淺出設計模式 (Head First Design Pattern) - 重點整理及範例分享35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言