二袱院、觀察者模式(Observer)

本章目錄如下:

????????一、階段一

????????二悔雹、階段二

????????三益涧、設(shè)計(jì)原則總結(jié)

本章需求是設(shè)計(jì)一個(gè)氣象展示應(yīng)用扭弧,并通過代碼迭代伊磺、優(yōu)化過程得出前人的設(shè)計(jì)經(jīng)驗(yàn)之一觀察者模式续崖。下面以代碼的迭代演化過程為線索介紹像吻。

一惭每、階段一

需求:氣象監(jiān)測站希望創(chuàng)建一個(gè)氣象展示應(yīng)用置鼻,默認(rèn)有三個(gè)布告板蛛碌,且允許第三方接入/離開誊辉。監(jiān)測站提供WeatherData類,在氣象數(shù)據(jù)變化時(shí)氣象站調(diào)用WeatherData對象的measurementsChanged方法來更新氣象數(shù)據(jù)蛙紫。

需求分析:我們只需要在WeatherData類的measurementsChanged方法中獲取氣象數(shù)據(jù)途戒,并更新我們的氣象板即可矢渊。

代碼實(shí)現(xiàn)如下:

public class WeatherData{

????????//實(shí)例變量聲明秒赤,氣象站已經(jīng)實(shí)現(xiàn)

????public void measurementsChanged() {

?????????//首先鞍泉,調(diào)用 WeatherData 的三個(gè)getXxx()方法,以取得最近的測量值仗处。這些getXxx()方法氣象站已經(jīng)實(shí)現(xiàn)好了眯勾。

????????float temp = getTemperature() ;

????????float humidity = getHumidity() ;?

???????float pressure = getPressure() ;

????????//其次,更新布告板

????????currentConditionsDisplay . update (temp, humidity, pressure) ;

????????statisticsDisplay .update (temp, humidity, pressure) ;?

???????forecastDisplay .update (temp, humidity, pressure) ;?

???}

????//這里是其他WeatherData方法婆誓,,氣象站已經(jīng)實(shí)現(xiàn)

}

該實(shí)現(xiàn)的缺點(diǎn):面對需求也颤,首先要找出變化洋幻,將變化分離出來,然后在依據(jù)設(shè)計(jì)原則挑選合適的設(shè)計(jì)模式翅娶。本章需求的變化之處是允許第三方接入文留,那么我們就需要將“允許第三方接入”功能分離出來好唯,如果像階段一的代碼一樣,不分離的話會(huì)使代碼不能擴(kuò)展和維護(hù)燥翅。下面我們進(jìn)入第二階段:優(yōu)化骑篙。

二、階段二

從報(bào)紙訂閱的角度來講森书,觀察者模式=出版者+訂閱者靶端;從理論定義角度來講,觀察者模式=主題(Subject)/可觀察者(Observable)+觀察者(Observer)凛膏。定義:觀察者模式定義了對象之間的一對多依賴杨名, 這樣一來,當(dāng)一個(gè)對象改變狀態(tài)時(shí)猖毫,它的所有依賴者都會(huì)收到通知并自動(dòng)更新台谍。觀察者模式類圖如下:

為什么要在主題實(shí)現(xiàn)類中加入一些get方法?因?yàn)橹黝}發(fā)送的信息可能有很多是觀察者不需要的數(shù)據(jù)吁断,主題實(shí)現(xiàn)類中加入get方法可以使觀察者接收到主題對象推送時(shí)主動(dòng)去拉去數(shù)據(jù)趁蕊。

類圖解釋說明:

? ? (1)、主期只知道觀察者實(shí)現(xiàn)了某個(gè)核口(也就是Observer接口) 仔役,主題不需要知道觀察者的具體類是誰介衔,做了些什么或其他任何細(xì)節(jié)。

? ? (2)骂因、任何時(shí)候我們都可以增加新的觀察者炎咖,因?yàn)橹黝}唯依賴的東西是一個(gè)實(shí)現(xiàn)Observer接口的對象列表,所以我們可以隨時(shí)增加觀察者寒波。

? ? (3)乘盼、有新類型的觀察者出現(xiàn)時(shí),主題的代碼不需要修改俄烁。

? ? (4)绸栅、因?yàn)閮烧呤撬珊系模淖冎黝}或觀察者其中一方页屠,并不會(huì)影響另一方粹胯,所以只要他們之間的接口仍被遵守,我們就可以自由地改變他們辰企。所以可以獨(dú)立地復(fù)用主題或觀察者风纠。

松耦合的威力:當(dāng)兩個(gè)對象之間松耦合,它們依然可以交互牢贸,但是不太清楚彼此的細(xì)節(jié)竹观。松糊合的設(shè)計(jì)之所以能讓我們建立有彈性的00系統(tǒng),能夠應(yīng)對變化,是因?yàn)閷ο笾g的互相依賴降到了最低臭增。觀察者模式讓主題和觀察者之間松耦合懂酱。

設(shè)計(jì)原則3:為了交互對象之間的松耦合設(shè)計(jì)而努力

根據(jù)以上對觀察者模式的說明和新的設(shè)計(jì)原則的了解誊抛,我們將氣象站的新類圖設(shè)計(jì)如下:

氣象站代碼如下:

public interface Subject {//Subject接口

????public void registerObserver(Observer o);

????public void removeObserver(Observer o);

????public void notifyObservers();

}

public interface Observer {//Observer接口

????public void update(float temp, float humidity, float pressure);

}

public interface DisplayElement {//DisplayElement接口

????public void display();

}

=============================氣象站subject實(shí)現(xiàn)類======================

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 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 (Observer observer : observers) {

????????????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();

????}

????public float getTemperature() {

????????return temperature;

????}

????public float getHumidity() {

????????return humidity;

????}

????public float getPressure() {

????????return pressure;

????}

}

==========================當(dāng)前狀況布告板============================

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");

????}

}//統(tǒng)計(jì)布告板列牺、預(yù)測布告板請參考源碼

=============================測試氣象站==============================

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);

????}

}

Java API內(nèi)置了觀察者模式,即java.util包 (package) 中的Observable類與Observer接口拗窃。Observable類中實(shí)現(xiàn)了addObserver(Observer o)瞎领、deleteObserver(Observer o)、notifyObservers()并炮、setChanged()方法默刚,主題實(shí)現(xiàn)類繼承該類即可使用這些方法。需要注意兩點(diǎn):

? ? ? ? (1)逃魄、使用前需要導(dǎo)入import java.util.Observable和import java.util.Observer包

? ? ? ? (2)荤西、調(diào)用notifyObservers()之前需要先調(diào)用setChanged()來指示狀態(tài)已經(jīng)改變。

三伍俘、設(shè)計(jì)原則總結(jié)

設(shè)計(jì)原則1:找出應(yīng)用中可能需要變化之處邪锌,把它們獨(dú)立出來,不要和那些不需要變化 T個(gè)T的代碼混在一起癌瘾。該設(shè)計(jì)原則作用: “把會(huì)變化的部分取出并封裝起來觅丰,以便以后可以輕易地改動(dòng)或擴(kuò)充此部分,而不影響不需要變化的其他部分”妨退。

設(shè)計(jì)原則2:針對接口編程妇萄,而不是針對實(shí)現(xiàn)編程。===我的理解是這個(gè)原則的使用優(yōu)先級排在“設(shè)計(jì)原則1:變化原則”之后咬荷,即該原則是一個(gè)在大模式已確定需要實(shí)現(xiàn)具體類時(shí)針對實(shí)現(xiàn)類采用的原則冠句,針對范圍比較小。

設(shè)計(jì)原則3:為了交互對象之間的松耦合設(shè)計(jì)而努力幸乒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末懦底,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子罕扎,更是在濱河造成了極大的恐慌聚唐,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腔召,死亡現(xiàn)場離奇詭異杆查,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)宴咧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進(jìn)店門根灯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人掺栅,你說我怎么就攤上這事烙肺。” “怎么了氧卧?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵桃笙,是天一觀的道長。 經(jīng)常有香客問我沙绝,道長搏明,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任闪檬,我火速辦了婚禮星著,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘粗悯。我一直安慰自己虚循,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布样傍。 她就那樣靜靜地躺著横缔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪衫哥。 梳的紋絲不亂的頭發(fā)上茎刚,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天,我揣著相機(jī)與錄音撤逢,去河邊找鬼膛锭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蚊荣,可吹牛的內(nèi)容都是我干的初狰。 我是一名探鬼主播,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼妇押,長吁一口氣:“原來是場噩夢啊……” “哼跷究!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起敲霍,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤俊马,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后肩杈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柴我,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年扩然,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了艘儒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,865評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖界睁,靈堂內(nèi)的尸體忽然破棺而出觉增,到底是詐尸還是另有隱情,我是刑警寧澤翻斟,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布逾礁,位于F島的核電站,受9級特大地震影響访惜,放射性物質(zhì)發(fā)生泄漏嘹履。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一债热、第九天 我趴在偏房一處隱蔽的房頂上張望砾嫉。 院中可真熱鬧,春花似錦窒篱、人聲如沸焕刮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽济锄。三九已至,卻和暖如春霍转,著一層夾襖步出監(jiān)牢的瞬間荐绝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工避消, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留低滩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓岩喷,卻偏偏與公主長得像恕沫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子纱意,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內(nèi)容