<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    合工大很牛很牛牛

      BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
      14 Posts :: 1 Stories :: 37 Comments :: 0 Trackbacks
     

    下面做一個天氣預(yù)報(bào)系統(tǒng),涉及到的參數(shù)一共有三種:temperature, humidity, pressure。外圍接受顯示裝置也分為三種:current condition display會列出當(dāng)前的氣溫,濕度和氣壓;statistics display會列出當(dāng)前的溫度最高,最低和平均值;forecast display列出將來預(yù)測的天氣狀況。現(xiàn)在我們設(shè)想用一個WeatherDataObject這個對象從氣象臺實(shí)時接受數(shù)據(jù),再把更新的數(shù)據(jù)發(fā)送到外圍接受顯示裝置上去。如下:

    我們先看右邊的三個顯示設(shè)備,我們把它跟前一章的Duck做比較:Duck是一個總稱,被做成抽象類,下面有許多各種各樣的duck,被做成該抽象類的子類,Duck的各種會變化的功能比如quackableflyable被分別做成接口,每個接口下面有各種具體的功能實(shí)現(xiàn)它。同理,這個天氣情況顯示設(shè)備也好比是一個總稱,下面有三種顯示設(shè)備,而它的可變化的功能是display,因?yàn)槲磥砜赡茉僮龅谒姆N設(shè)備是用聲音報(bào)警的。。。

    因?yàn)槭菍?shí)時接受和顯示數(shù)據(jù),所以所有的設(shè)備必然包含update()功能,部分設(shè)備有display功能。UML如下:

    public interface Observer
    {

        public void update(float temperature, float humidity, float pressure);
    }

    public interface Display
    {

        public void display();
    }

    public class CurrentCondition implements Observer, Display
    {

        private float temperature;
        private float humidity;

        public void display()
        {
            System.out.println("Current conditions: " + temperature + "F degrees and humidity " + humidity);
        }

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

    public class Statistics implements Display, Observer
    {

        private static float maxT = 0;//歷史最高氣溫
        private static float minT = 100;//
    歷史最低氣溫
        private static float sumT = 0;//
    氣溫總和
        private static int num = 0;//
    測量次數(shù)
        public void display()
        {
            System.out.println("Max Temperature:"+maxT);
            System.out.println("Min Temperature:"+minT);
            System.out.println("Average Temperature:"+sumT/num);
        }

        public void update(float temperature, float humidity, float pressure)
        {
            if (temperature < minT)
            {
                minT = temperature;
            }
            if (temperature > maxT)
            {
                maxT = temperature;
            }
            sumT += temperature;
            num++;
            display();
        }
    }

    public class Forecast implements Display, Observer
    {

       private static float currentPressure = 29;//設(shè)定一個當(dāng)前氣壓的默認(rèn)值,為簡化操作
        private static  float lastPressure = 29;//
    設(shè)定一個先前氣壓的默認(rèn)值

        public void display()
        {
            System.out.println("Forecast:");
            if (currentPressure > lastPressure) //
    氣壓升高,天氣轉(zhuǎn)暖;氣壓降低,天氣轉(zhuǎn)涼
            {
                System.out.println("will be warmmer.");
            }
            else if (currentPressure == lastPressure)
            {
                System.out.println("will be the same");
            }
            else
            {
                System.out.println("will be cooler");
            }
        }

        public void update(float temperature, float humidity, float pressure)
        {
            lastPressure = currentPressure;
            currentPressure = pressure;
            display();
        }
    }

     

    現(xiàn)在著重考慮WeatherData 這個對象怎么寫,該對象首先要能夠從氣象站收取氣溫,濕度,氣壓的信息(通過氣象臺使用setMeasurements方法來設(shè)定WeatherData中的各屬性的值),并向終端顯示設(shè)備更新氣象信息(使用upadeDisplay方法),所以有:

    public class WeatherData
    {
        private float temperature;
        private float humidity;
        private float pressure;

        public void updateDisplay()
        {
            CurrentCondition currentCondition=new CurrentCondition();
            Statistics statistics=new Statistics();
            Forecast forecast=new Forecast();
           
    currentCondition.update(temperature, humidity, pressure); //這部分是可變動的,可是并沒有被分離出去
            statistics.update(temperature, humidity, pressure);
            forecast.update(temperature, humidity, pressure);

        }

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

     

    最后我們用個主函數(shù)來調(diào)試一下:

    public class Main
    {

        public static void main(String[] args)
        {
            WeatherData wd=new WeatherData();
            wd.setMeasurements(20, 10, 15);
            wd.setMeasurements(21, 11, 16);
        }
    }

    輸出:

    Current conditions: 20.0F degrees and humidity 10.0
    Max Temperature:20.0
    Min Temperature:20.0
    Average Temperature:20.0
    Forecast:
    will be cooler
    Current conditions: 21.0F degrees and humidity 11.0
    Max Temperature:21.0
    Min Temperature:20.0
    Average Temperature:20.5
    Forecast:
    will be warmmer.

    可以看出,一切運(yùn)行正常,是不是這樣,該程序就搞定了呢?當(dāng)然不是!當(dāng)我們不想讓三個終端中的某一個接受天氣信息時,或者我們要增加一個新的終端來顯示其他的一些天氣信息時,我們勢必要改寫WeatherDate中的updateDisplay方法(上面源代碼中的紅字部分)。我們并沒有把WeatherDate中的不變化的setMeasurements方法和變化的updateDisplay方法分離開,也就是說沒有隔離出變化的部分,所以這個程序有待改進(jìn)。

    可不可以把updateDisplay寫成接口的形式分離出去呢?Good Idea! 不過updateDisplay之所以產(chǎn)生變化,不是像Duckflyable那樣是功能性的變化,而是updateDisplay方法體本身中的執(zhí)行過程需要增減。所以即使把updateDisplay作為接口分離出去,這個接口也要不斷的改變,多以我們對這類增減某一類似問題所產(chǎn)生的變化引入observer pattern

    所謂的observer pattern即是實(shí)現(xiàn)觀察者和觀察對象之間關(guān)系的一種模式。該模式中,觀察對象可以有一個,也可以有多個。如果觀察者要實(shí)時接受觀察對象的信息,就必須通過該觀察對象的registerObserver方法注冊成為該觀察對象的觀察者群。也可以通過removeObserver方法注銷并離開該觀察對象的觀察者群。觀察對象通過notifyObserver方法將實(shí)時信息通知給它所有的已注冊的觀察者。

    observer pattern的本質(zhì)實(shí)質(zhì)是1對多的關(guān)系:每一個觀察對象可以對應(yīng)著許多觀察者,而每一個觀察者又可以觀察許多觀察對象

     

    把這種思路放到目前我們需要解決的氣象站的例子上去:

     

    較前面的實(shí)現(xiàn)方式,主要變化的代碼如下:

    public interface Subject
    {
         //
    之所以要寫一個接口而不直接使用WeatherData類,是因?yàn)樵摻涌谙旅婵赡懿恢?/span>WeatherData這一個實(shí)現(xiàn)對象
        public void registerObserver(
    Observer o);

        public void removeObserver(Observer o);

        public void notifyObservers();
    }

     

    import java.util.ArrayList;

    public class WeatherData implements Subject
    {

        private float temperature;
        private float humidity;
        private float pressure;
        private ArrayList<Observer> observers = new ArrayList<Observer>();

        public WeatherData()
        {
        }

        public void setMeasurement(float temperature, float humdity, float pressure)
        {   //
    氣象站使用該方法設(shè)置新的氣象數(shù)值,并通知所有已注冊觀察者
            this.temperature = temperature;
            this.humidity = humdity;
            this.pressure = pressure;
            notifyObservers();
        }

        public void registerObserver(Observer o) //注冊觀察者
        {
            observers.add(o);
        }

        public void removeObserver(Observer o) //注銷觀察者
        {
            if (observers.indexOf(o) >= 0)
            {
                observers.remove(o);
            }
        }

        public void notifyObservers() //通知所有的已注冊的觀察者新信息
        {
            for (Observer o : observers)
            {
                o.update(temperature, humidity, pressure);
            }
        }
    }

    public class Main
    {
        public static void main(String[] args)
        {
            WeatherData wd=new WeatherData();
            CurrentCondition cc=new CurrentCondition();
            wd.registerObserver(cc); //
    注冊CurrentCondition顯示方式到WeatherData的觀察者群中去
            Statistics st=new Statistics();
            wd.registerObserver(st);   //
    同理,注冊Statistics的顯示方式
            wd.setMeasurement(20, 10, 15);
            wd.setMeasurement(21, 11, 16);       
            System.out.println("===================
    我是分割線=================");
            wd.removeObserver(st); //
    注銷Statistics的顯示方式
            wd.setMeasurement(19, 9, 14);
        }
    }

     

    運(yùn)行結(jié)果如下;

    Current conditions: 20.0F degrees and humidity 10.0
    Max Temperature:20.0
    Min Temperature:20.0
    Average Temperature:20.0
    Current conditions: 21.0F degrees and humidity 11.0
    Max Temperature:21.0
    Min Temperature:20.0
    Average Temperature:20.5
    ===================
    我是分割線=================
    Current conditions: 19.0F degrees and humidity 9.0

     

    由此,我們可以看到,我們能夠在Main方法中動態(tài)的注冊和注銷某被觀察對象的已注冊的觀察者,達(dá)到了我們預(yù)期的目的。

    現(xiàn)在我們嘗試新增一個顯示方式HeatIndexheat index是熱指數(shù),它的計(jì)算方法為:heatIndex=16.923+1.85212*temperature+5.37941*humidity

    很簡單,我們只要寫一個新的類,實(shí)現(xiàn)ObserverDisplayElement接口就可以了,在主程序Main中,我們再把這個顯示方式注冊到WeatherData的觀察者中去。

    public class HeatIndex implements Observer, Display
    {

        private float temperature;
        private float humidity;

        public HeatIndex()
        {
        }

        public void display()
        {
            float heatIndex = (float) (16.923 + 1.85212 * temperature + 5.37941 * humidity);
            System.out.println("Heat Index is " + heatIndex);
        }

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

    public class Main
    {

        public static void main(String[] args)
        {
            WeatherData wd = new WeatherData();
            CurrentCondition cc = new CurrentCondition();
            wd.registerObserver(cc);
            Statistics st = new Statistics();
            wd.registerObserver(st);
            wd.setMeasurement(20, 10, 15);
            wd.setMeasurement(21, 11, 16);
            System.out.println("===================
    我是分割線=================");
            wd.removeObserver(st);
        
       HeatIndex hi = new HeatIndex();
            wd.registerObserver(hi);  
        
            wd.setMeasurement(19, 9, 14);
        }
    }

    運(yùn)行結(jié)果如下:

    Current conditions: 20.0F degrees and humidity 10.0
    Max Temperature:20.0
    Min Temperature:20.0
    Average Temperature:20.0
    Current conditions: 21.0F degrees and humidity 11.0
    Max Temperature:21.0
    Min Temperature:20.0
    Average Temperature:20.5
    ===================
    我是分割線=================
    Current conditions: 19.0F degrees and humidity 9.0
    Heat Index is 100.52797

    可見,我們很輕松的就添加了一個顯示方式,并動態(tài)的注冊到相應(yīng)的觀察者中,而且最重要的是:我們沒有對源代碼做任何更改。

     

    posted on 2008-07-18 00:54 化的了 閱讀(1646) 評論(2)  編輯  收藏 所屬分類: 設(shè)計(jì)模式

    Feedback

    # re: Observer Pattern 觀察者模式 2008-07-18 11:23 Edward Li
    您好,您寫的文章很不錯,但是我有個疑問,加入subject之后里面的obsever的add方法是哪里來的。 我個人覺得你講的內(nèi)容已經(jīng)是依賴注入模式了,而observer模式僅僅是設(shè)置一個observer方法來監(jiān)控某個方法狀態(tài)轉(zhuǎn)換的模式,很顯然你講的超出了這個范圍了。總結(jié)一下就是你講的是依賴注入+observer.不知道你怎么看這個問題。請及時回復(fù)我  回復(fù)  更多評論
      

    # re: Observer Pattern 觀察者模式 2008-12-25 01:13 zkenshin
    看看head first design pattern會發(fā)現(xiàn)雷同得不得了
    如果本文作者做的工作只是翻譯 請說明 以免混淆  回復(fù)  更多評論
      

    主站蜘蛛池模板: 亚洲综合色视频在线观看| 亚洲精品无码日韩国产不卡?V| 亚洲精品白色在线发布| 国产亚洲福利一区二区免费看| 国产亚洲福利精品一区二区| 免费高清在线爱做视频| 亚洲成熟丰满熟妇高潮XXXXX | 九月婷婷亚洲综合在线| 亚洲国产精品成人综合色在线| 欧洲亚洲综合一区二区三区| 夜夜爽免费888视频| 亚洲第一se情网站| 中文字幕亚洲一区| 精品国产免费一区二区三区香蕉 | 日韩免费高清视频| 亚洲国产一区二区三区在线观看| 久久久久久av无码免费看大片| 91手机看片国产永久免费| 亚洲国产夜色在线观看| 午夜视频免费成人| selaoban在线视频免费精品| 亚洲AV日韩AV天堂一区二区三区 | 在线观看亚洲成人| 国产成人无码区免费内射一片色欲| 在线a人片天堂免费观看高清| 亚洲精品高清国产一线久久| 成在线人免费无码高潮喷水| 亚洲人成网站在线播放影院在线 | 亚洲国产精品毛片av不卡在线| 亚洲人妖女同在线播放| 国产免费人成视频在线观看| 中文在线免费看视频| 亚洲国产精品日韩在线观看 | 日韩亚洲不卡在线视频中文字幕在线观看| 国产亚洲情侣久久精品| 亚洲无码高清在线观看| 99热这里有免费国产精品| 亚洲人成未满十八禁网站| 亚洲色图综合在线| 国产1024精品视频专区免费| 欧亚一级毛片免费看|