[head first 設計模式]第二章 觀察者模式
假如我們有一個開發需求——建造一個氣象觀測站展示系統,需求方給我們提供了一個WeatherObject物件,能夠自動獲得最新的測量資料,而我們要建立一個應用,有三種布告版,分別顯示目前的狀況,氣象統計,簡單預報,三種布告板能即時顯示WeatherObject物件中更新的資料,
?同時,我們需要這是一個可擴展的氣象站,可以公布一組api,好讓其他開發人員寫出自己的布告板插入此應用中,
?我們首先來看看我們的大致系統框架

我們的作業就算建立一個應用,利用weatherData物件取得資料,并更新布告板,
根據weatherData源檔案,我們的作業是實作measurementChanged(),當測量資料備妥時,measurementChanged()方法將會被呼叫,

先來看一個可能的實作,

很明顯,這個實作并不妥當,回想第一章的OO原則,會發現我們在針對具體實作編程,這會導致當有新需求時我們必須修改程式,同時,更新布告板的代碼會經常改變,我們應該盡可能將其封裝,
接下來我們將應用觀察者模式來改進現有設計,
以報紙訂閱為例,我們像某家報社訂閱報紙,只要他們有新報紙初版,就會給派送給訂戶,而訂戶不想要了,就可以取消訂閱,只要報社還在運營,就不斷有人訂閱或者取消訂閱報紙,
出版者+訂閱者=觀察者模式
如果了解了報紙訂閱是怎么回事,觀察者模式也大體如此,出版者即為觀察者模式中的主題(Subject),訂閱者即為觀察者模式中的觀察者(Observer),

定義觀察者模式
觀察者模式定義了物件之間的一對多依賴,這樣一來,當一個物件改變狀態時,它的所有依賴著都會收到通知并自動更新,
類圖如圖所示

觀察者模式提供了一種物件設計,讓主題和觀察者之間松耦合,
對于觀察者,主題只關心觀察者實作了Observer介面,主題并不關心觀察者的細節,
任何時候都可以新增觀察者,因為主題唯一以來的東西是一個實作了Observer介面的物件串列,同時,也可以在任何時候洗掉觀察者,
改變主題或觀察者中的其中一方,并不會影響到另一方,
設計原則
設計應該盡可能降低互動物件之間的耦合度
依照觀察者模式,得到我們的新設計

當前,我們暫時不用Java內置的觀察者模式,而是自己實作這部分代碼,
public interface Observer {
public void update(float temp,float humidity,float pressure);
}
public interface Subject {
public void notifyObserver();
public void removeObserver(Observer observer);
public void registerObserver(Observer observer);
}
public interface DisplayElement {
public void display();
}
import java.util.ArrayList;
import java.util.List;
public class WeatherData implements Subject {
private List<Observer> Observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData()
{
Observers = new ArrayList<Observer>();
}
@Override
public void notifyObserver() {
for (Observer o:
Observers ) {
o.update(temperature,humidity,pressure);
}
}
@Override
public void removeObserver(Observer observer) {
Observers.remove(observer);
}
@Override
public void registerObserver(Observer observer) {
Observers.add(observer);
}
public void measurementChanged()
{
notifyObserver();
}
public void setMeasurements(float temperature,float humidity,float pressure)
{
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementChanged();
}
}
public class CurrentConditionsDisplay implements Observer,DisplayElement{
private float temperature;
private float humidity;
private Subject weatherData;
@Override
public void display() {
System.out.println("Current conditions: "+temperature+"F degrees and "+humidity+"% humidity");
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
public CurrentConditionsDisplay( Subject weatherData) {
this.weatherData = https://www.cnblogs.com/alex101/archive/2020/11/23/weatherData;
weatherData.registerObserver(this);
}
}
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = https://www.cnblogs.com/alex101/archive/2020/11/23/new WeatherData();
CurrentConditionsDisplay currentConditionsDisplay =
new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80,65,30.4f);
}
}
使用Java內置的觀察者模式
Java api有自帶的觀察者模式,包含Observer介面和Observable類,在使用上更加方便,很多功能已經事先準備好了,如下是我們使用Java內置觀察者模式修改后的設計,

注冊/洗掉觀察者
呼叫Observable物件的addObserver方法和deleteObserver方法即可
被觀察者送出通知
首先呼叫setChanged()方法,標記狀態已經改變,后呼叫notifyObservers(),那么所有觀察者都會呼叫自身的update方法,
import java.util.Observable;
import java.util.Observer;
public class CurrentConditionsDisplay implements Observer,DisplayElement{
private double temperature;
private double humidity;
private Observable observable;
@Override
public void display() {
System.out.println("Current temperature "+temperature+"F degrees and "+humidity+"%humidity");
}
public CurrentConditionsDisplay(Observable observable)
{
this.observable = observable;
observable.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
if(o instanceof WheatherData)
{
temperature = ((WheatherData) o).getTemperature();
humidity = ((WheatherData) o).getHumidity();
display();
}
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
public class WheatherData extends Observable {
private double temperature;
private double humidity;
private double pressure;
public double getHumidity() {
return humidity;
}
public double getPressure() {
return pressure;
}
public double getTemperature()
{
return temperature;
}
public void setMeasurements(double temperature,double humidity,double pressure)
{
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
setChanged();
notifyObservers();
}
}
不幸的是,observable是一個類而不是介面,導致我們難以繼承其他類,同時也無法擁有自己獨特的實作,
在實際使用時,我們需要權衡是使用jdk自帶的觀察者模式亦或是由自己實作,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/227134.html
標籤:其他
