<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                #### **一、觀察者模式簡單實現(一)之追劇** > 這里舉一個追劇的例子,平常為了不錯過最新的電視劇我們會訂閱或關注這個電視劇,當電視劇更新后會第一時間推送給我們,下來就簡單實現一下。 >[info] 注意,主題中的方法可能與我們前面的圖示中的不一樣,當然具體問題具體分析。 * **抽象觀察者類(Observer)** ~~~ /** * 抽象觀察者類,為所有具體觀察者定義一個接口,在得到通知時更新自己 */ public interface Observer { /** * 有更新 * * @param message 消息 */ public void update(String message); } ~~~ * **抽象被觀察者(抽象主題)** ~~~ /** * 抽象被觀察者類 */ public interface Observable { /** * 推送消息 * * @param message 內容 */ void push(String message); /** * 訂閱 * * @param observer 訂閱者 */ void register(Observer observer); } ~~~ * **具體的觀察者類(ConcreteObserver)** ~~~ /** * 具體的觀察者類,也就是訂閱者 */ public class User implements Observer { @Override public void update(String message) { System.out.println(name + "," + message + "更新了!"); } // 訂閱者的名字 private String name; public User(String name) { this.name = name; } } ~~~ * **具體的被觀察者類(具體主題)** ~~~ /** * 具體的被觀察者類,也就是訂閱的節目 */ public class Teleplay implements Observable{ private List<Observer> list = new ArrayList<Observer>();//儲存訂閱者 @Override public void push(String message) { for(Observer observer:list){ observer.update(message); } } @Override public void register(Observer observer) { list.add(observer); } } ~~~ * **實現** ~~~ public class Client { public static void main(String[] args) { //被觀察者,這里就是用戶訂閱的電視劇 Teleplay teleplay = new Teleplay(); //觀察者,這里就是訂閱用戶 User user1 = new User("小明"); User user2 = new User("小光"); User user3 = new User("小蘭"); //訂閱 teleplay.register(user1); teleplay.register(user2); teleplay.register(user3); //推送新消息 teleplay.push("xxx電視劇"); } } ~~~ * **結果** ~~~ 小明,xxx電視劇更新了! 小光,xxx電視劇更新了! 小蘭,xxx電視劇更新了! ~~~ **總結**:由上面的代碼可以看出實現了一對多的消息推送,推送消息都是依賴Observer和Observable這些抽象類,而User和Teleplay完全沒有耦合,保證了訂閱系統的靈活性和可擴展性。 **觀察者模式主要的作用就是對象解耦,將觀察者和被觀察者完全隔離,只依賴于Observer和Observable抽象。** #### **二、簡單實現(二)之氣象監測應用** :-: ![](https://box.kancloud.cn/382630a8883d40bf89a07ebaab918617_937x562.jpg) 圖1 氣象站 如圖所示:系統分為3部分,**氣象站**(獲取是極其想的物理裝置)、**WeatherData對象**(追蹤來自氣象站的數據,并更新布告板)、**布告板**(顯示目前天氣狀況給用戶看)。 **WeatherData對象是主題,布告板是觀察者。有3個使用天氣數據的布告板:目前狀態布告板、氣象統計布告板、天氣預報布告板。一旦WeatherData有更新,這些布告板必須馬上更新。此系統還可以擴展,讓開發人員建立定制的布告板。** :-: ![](https://box.kancloud.cn/3a09d9d237ec9a35584dcffbc87ccd2e_676x656.jpg) 圖2 氣象站具體設計 ##### **具體實現** **Subject.java(抽象主題)** ~~~ package headfirst.observer.weather; public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); } ~~~ **Observer.java(抽象觀察者)** ~~~ package headfirst.observer.weather; public interface Observer { public void update(float temp, float humidity, float pressure); } ~~~ **DisplayElement.java** ~~~ package headfirst.observer.weather; public interface DisplayElement { public void display(); } ~~~ **氣象站(具體主題)** **WeatherData.java** ~~~ package headfirst.observer.weather; import java.util.*; public class WeatherData implements Subject { private ArrayList observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList(); } public void registerObserver(Observer o) { observers.add(o); } public void removeObserver(Observer o) { int i = observers.indexOf(o); if (i >= 0) { observers.remove(i); } } public void notifyObservers() { for (int i = 0; i < observers.size(); i++) { Observer observer = (Observer)observers.get(i); observer.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(); } // other WeatherData methods here public float getTemperature() { return temperature; } public float getHumidity() { return humidity; } public float getPressure() { return pressure; } } ~~~ **布告板(具體觀察者)**:具體的布告板 **目前狀況:CurrentConditionsDisplay.java** ~~~ package headfirst.observer.weather; public class CurrentConditionsDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private Subject weatherData; public CurrentConditionsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(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 + "F degrees and " + humidity + "% humidity"); } } ~~~ **氣象統計:StatisticsDisplay.java** ~~~ package headfirst.observer.weather; import java.util.*; public class StatisticsDisplay implements Observer, DisplayElement { private float maxTemp = 0.0f; private float minTemp = 200; private float tempSum= 0.0f; private int numReadings; private WeatherData weatherData; public StatisticsDisplay(WeatherData weatherData) { this.weatherData = weatherData; weatherData.registerObserver(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); } } ~~~ **天氣預報:ForecastDisplay.java** ~~~ package headfirst.observer.weather; import java.util.*; public class ForecastDisplay implements Observer, DisplayElement { private float currentPressure = 29.92f; private float lastPressure; private WeatherData weatherData; public ForecastDisplay(WeatherData weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } public void update(float temp, float humidity, float pressure) { lastPressure = currentPressure; currentPressure = pressure; display(); } public void display() { System.out.print("Forecast: "); if (currentPressure > lastPressure) { System.out.println("Improving weather on the way!"); } else if (currentPressure == lastPressure) { System.out.println("More of the same"); } else if (currentPressure < lastPressure) { System.out.println("Watch out for cooler, rainy weather"); } } } ~~~ **測試程序** ~~~ package headfirst.observer.weather; import java.util.*; public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); } } ~~~ 輸出結果如下: :-: ![](https://box.kancloud.cn/af6c09a68cd5b8ac340c9b69270873a2_655x306.jpg) 圖3 氣象站輸出結果 如果還需要增加酷熱指數布告板,可以如下 **酷熱指數:HeatIndexDisplay.java** ~~~ package headfirst.observer.weather; public class HeatIndexDisplay implements Observer, DisplayElement { float heatIndex = 0.0f; private WeatherData weatherData; public HeatIndexDisplay(WeatherData weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } public void update(float t, float rh, float pressure) { heatIndex = computeHeatIndex(t, rh); display(); } private float computeHeatIndex(float t, float rh) { float index = (float)((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh) + (0.00941695 * (t * t)) + (0.00728898 * (rh * rh)) + (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) + (0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 * (rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) + (0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) + 0.000000000843296 * (t * t * rh * rh * rh)) - (0.0000000000481975 * (t * t * t * rh * rh * rh))); return index; } public void display() { System.out.println("Heat index is " + heatIndex); } } ~~~ 測試(增加酷熱指數布告板) **WeatherStationHeatIndex.java** ~~~ package headfirst.observer.weather; import java.util.*; public class WeatherStationHeatIndex { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); } } ~~~ 輸出結果 :-: ![](https://box.kancloud.cn/40fe3d2b11d5b8cbbb878e73ecdaa7ae_878x366.jpg) 圖4 氣象站輸出結果(增加酷熱指數) **二、1、簡單實現(二)之氣象監測應用(使用Java內置的觀察者模式來實現氣象站獲取數據并實時更新布告板的實例)** 修改后的氣象站OO設計如下 :-: ![](https://box.kancloud.cn/a89fca3f62e2aba7a99e613fecb3349c_980x643.jpg) 圖5 修改后的氣象站OO設計(使用java內置的觀察者) **主題(被觀察者)** **WeatherData.java** **WeatherData(主題)現在擴展自Observable(被觀察者),setChanged()方法用來標記已經改變的事實,好讓notifyObservers()知道它被調用時應該更新觀察者,如果notifyObservers()之前沒有先調用setChanged()方法,觀察者就不會被通知。setChanged()方法可以讓你在更新觀察者時,有更多的彈性,可以適當地通知觀察者。另外clearChanged()方法、hasChanged()方法有時也需要被用到。** ~~~ package headfirst.observer.weatherobservable; import java.util.Observable; import java.util.Observer; public class WeatherData extends Observable { private float temperature; private float humidity; private float pressure; public WeatherData() { } public void measurementsChanged() { setChanged(); notifyObservers(); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } public float getTemperature() { return temperature; } public float getHumidity() { return humidity; } public float getPressure() { return pressure; } } ~~~ **DisplayElement.java** ~~~ package headfirst.observer.weatherobservable; public interface DisplayElement { public void display(); } ~~~ **觀察者** **布告板(具體觀察者)** **目前狀況:CurrentConditionsDisplay.java** ~~~ package headfirst.observer.weatherobservable; import java.util.Observable; import java.util.Observer; public class CurrentConditionsDisplay implements Observer, DisplayElement { Observable observable; private float temperature; private float humidity; public CurrentConditionsDisplay(Observable observable) { this.observable = observable; observable.addObserver(this); } public void update(Observable obs, Object arg) { if (obs instanceof WeatherData) { WeatherData weatherData = (WeatherData)obs; this.temperature = weatherData.getTemperature(); this.humidity = weatherData.getHumidity(); display(); } } public void display() { System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity"); } } ~~~ **氣象統計:StatisticsDisplay.java** ~~~ package headfirst.observer.weatherobservable; import java.util.Observable; import java.util.Observer; public class StatisticsDisplay implements Observer, DisplayElement { private float maxTemp = 0.0f; private float minTemp = 200; private float tempSum= 0.0f; private int numReadings; public StatisticsDisplay(Observable observable) { observable.addObserver(this); } public void update(Observable observable, Object arg) { if (observable instanceof WeatherData) { WeatherData weatherData = (WeatherData)observable; float temp = weatherData.getTemperature(); 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); } } ~~~ **天氣預報:ForecastDisplay.java** ~~~ package headfirst.observer.weatherobservable; import java.util.Observable; import java.util.Observer; public class ForecastDisplay implements Observer, DisplayElement { private float currentPressure = 29.92f; private float lastPressure; public ForecastDisplay(Observable observable) { observable.addObserver(this); } public void update(Observable observable, Object arg) { if (observable instanceof WeatherData) { WeatherData weatherData = (WeatherData)observable; lastPressure = currentPressure; currentPressure = weatherData.getPressure(); display(); } } public void display() { System.out.print("Forecast: "); if (currentPressure > lastPressure) { System.out.println("Improving weather on the way!"); } else if (currentPressure == lastPressure) { System.out.println("More of the same"); } else if (currentPressure < lastPressure) { System.out.println("Watch out for cooler, rainy weather"); } } } ~~~ **酷熱指數:HeatIndexDisplay.java** ~~~ package headfirst.observer.weatherobservable; import java.util.Observable; import java.util.Observer; public class HeatIndexDisplay implements Observer, DisplayElement { float heatIndex = 0.0f; public HeatIndexDisplay(Observable observable) { observable.addObserver(this); } public void update(Observable observable, Object arg) { if (observable instanceof WeatherData) { WeatherData weatherData = (WeatherData)observable; float t = weatherData.getTemperature(); float rh = weatherData.getHumidity(); heatIndex = (float) ( (16.923 + (0.185212 * t)) + (5.37941 * rh) - (0.100254 * t * rh) + (0.00941695 * (t * t)) + (0.00728898 * (rh * rh)) + (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) + (0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 * (rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) + (0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) + (0.000000000843296 * (t * t * rh * rh * rh)) - (0.0000000000481975 * (t * t * t * rh * rh * rh))); display(); } } public void display() { System.out.println("Heat index is " + heatIndex); } } ~~~ 測試 **WeatherStation.java** ~~~ package headfirst.observer.weatherobservable; public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentConditions = new CurrentConditionsDisplay(weatherData); StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); } } ~~~ 輸出結果 :-: ![](https://box.kancloud.cn/e65734d9f61a7403976cbc736fce64ed_655x361.jpg) 圖6 氣象站輸出結果(使用Java內置的觀察者模式) 增加酷熱指數布告板的測試 **WeatherStationHeatIndex.java** ~~~ package headfirst.observer.weatherobservable; public class WeatherStationHeatIndex { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentConditions = new CurrentConditionsDisplay(weatherData); StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); } } ~~~ 從以上的圖3和圖6的結果對比來看,差別是文字輸出的次序不一樣了。原因在于Observable實現了它的notifyObservers()方法,導致了通知觀察者的次序不同于先前的次序,盡管誰也沒有錯,但是如果我們的代碼依賴這樣的次序就是錯的,因為一旦觀察者/可觀察者的實現有所改變,通知次序就會改變,很可能就會產生錯誤的結果。這不是我們所認為的松耦合。 #### **java.util.Observable的缺點** * **Observable(被觀察者)是一個類** **Observable是一個類,不是一個接口,甚至沒有實現一個接口**,如果想同時具有Observable類和另一個類的行為,就陷入兩難,因為Java不支持多繼承。再者,沒有Observable接口,所以無法建立自己的實現,和Java內置的Observe API搭配使用,也無法將java.util的實現換成另一套做法的實現。 * **Observable將關鍵的方法保護起來** 觀察Observable的API,可以發現setChanged()方法被保護起來,權限修飾符是protected,意味著:除非繼承自Observable,否則你無法創建Observable實例并組合到你自己的對象中。這設計違反了第二個設計原則:“多用組合,少用繼承”。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看