Observer模式的宗旨是在多個對象之間定義一對多的關系,以便當一個對象狀态改變的時候,其他所有依賴于這個對象的對象都能夠得到通知,并被自動更新。
1.經典範例:
借助于Observer模式,當某個對象發生變化時,關注該對象的其他對象可以被通知。這種模式的一個最常見的例子是圖形使用者界面。每當圖形界面的使用者單擊按鈕或者調整滑動條的時候,該應用程式中許多對象都會對此做出反應。Java開發者假定應用程式都會關心圖形界面使用者何時改變GUI元件。很顯然,Observer模式在Java Swing庫中得到了廣泛應用。在Java Swing架構中,關注Swing元件變化的類被稱為“監聽器”。我們可以為自己關心的每個事件注冊一個監聽器,以便元件事件發生的時候,我們能夠得到通知。
ShowBallistics類和BallisticsPanel類位于app.observer.ballistics包中。BallisticsFunction接口位于com.oozinoz.ballistics包中,它定義了燃燒速率和推進力曲線。該Java包中還有一個Ballisticstics工具類,它實作了BallisticsFunction接口。
這個彈道學應用程式在初始化滑動條的時候,将自己注冊為滑動條事件的監聽器。當滑動條滑動的時候,該應用程式就會更新用于顯示曲線的面闆和用于顯示tpeak值的标簽。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIw1mYuUTN4YGNxMGMyQGO50iZxMmYtkDM3MTLxEjY20yY2QTM2gTMj9CXyAjN1kzLcRnbl1GajFGd0F2LcRWYvxGc19CXt92YuUWelRXaukXeplHevw1LcpDc0RHaiojIsJye.bmp)
習題1:請完成ShowBallistics類的slider()方法和stateChanged()方法,該繪圖面闆和tpeak标簽能夠根據滑動條值的改變而顯示不同的曲線和資料。
public JSlider slider()
{ if(slider == null)
{ slider = new JSlider();
sliderMax = slider.getMaximum();
sliderMin = slider.getMinimum();
slider.addChangeListener(this);
slider.setValue(slider.getMinimum());
}
return slider;
}
public void stateChanged(ChangeEvent e)
{ double val = slider.getValue();
double tp = (val - sliderMin)/(sliderMax - sliderMin);
burnPanel().setTPeak(tp);
thrustPanel().setTPeak(tp);
valueLabel().setText(Format.formatToNPlace(N,2);
}
ShowBallistics類根據滑動條的值更新燃燒速率面闆、推進力面闆以及顯示tpeak值的标簽。這種設計方式很常見,雖然它不是很糟糕,但值得注意的是,它與Observer模式的意圖完全相悖!Java Swing架構采用Observer模式,以便滑動條無需了解那些使用者關注自己。但是ShowBallistics使我們重新面臨這種本希望避免的狀況:将單個依賴滑動條元件的對象---即它自身--注冊為滑動條事件的監聽器,在得到滑動條事件通知之後,該對象又将事件分發給各個相關的對象。在這種設計方式中,該對象必須清楚哪些對象依賴于滑動條元件,而這些依賴滑動條元件的對象并沒有注冊自己以監聽滑動條事件。
為了與Observer模式的意圖保持一緻,我們可以對上面的代碼進行一下改動,進而讓關注滑動條變化的元件直接注冊自己以監聽滑動條事件。這種新的設計的類圖如下:
在新的設計中,我們可以将addChangeListener()方法的調用從slider()方法中移出來,移到各個依賴滑動條的元件的構造器中:
public BallisticsPanel2(BallisticsFunction func,JSlider slider)
{
this.func = func;
this.slider = slider;
slider.addChangeListener(this);
}
每當滑動條滑動BallisticsPanel2類對象便會得到通知,然後标簽會重新計算并顯示tpeak值: