Java程式效能優化 讀書筆記(六)設計模式:觀察者模式
一、觀察者模式
觀察者模式定義了物件間的一種一對多依賴關係,使得每當一個物件改變狀態,則所有依賴於它的物件都會得到通知並被自動更新。它將觀察者和被觀察者的物件分離開。提高了應用程式的可維護性和重用性。觀察者模式又稱為釋出/訂閱(Publish/Subscribe)模式。
觀察者模式的應用場景:
1、 對一個物件狀態的更新,需要其他物件同步更新,而且其他物件的數量動態可變。
2、 物件僅需要將自己的更新通知給其他物件而不需要知道其他物件的細節。
觀察者模式的優點:
1、 Subject和Observer之間是鬆耦合的,分別可以各自獨立改變。
2、 Subject在傳送廣播通知的時候,無須指定具體的Observer
3、 遵守大部分GRASP原則和常用設計原則,高內聚、低偶合。
觀察者模式的缺陷:
1、 鬆偶合導致程式碼關係不明顯,有時可能難以理解。
2、 如果一個Subject被大量Observer訂閱的話,在廣播通知的時候可能會有效率問題。
二、觀察者模式的實現
實現觀察者模式有很多形式,一種是“註冊---通知---撤銷註冊”的形式。
1. 觀察者Observer:所有潛在的觀察者必須實現觀察者介面,這個介面只有update方法,當主題改變時,它被呼叫。
public interface Observer { public void update(float temprature); }
2. 具體觀察者ConcreteObserver: 具體觀察者可以是任何實現了Observer介面的類。觀察者必須註冊具體主題,一邊接收更新。
public class ConcreteObserver implements Observer { private float temperature; private final Subject subject; public ConcreteObserver(final Subject subject) { this.subject = subject; this.subject.registerObserver(this); } public float getTemperature() { return temperature; } public void setTemperature(final float temperature) { this.temperature = temperature; } @Override public void update(final float temperature) { this.temperature = temperature; } }
3. 可觀察者Subject: 主題介面,即可觀察者Observable,物件使用此介面註冊為觀察者,或者把自己從觀察者中刪除,每個主題可以有多個觀察者。
public interface Subject
{
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
4. 具體可觀察者ConcreteSubject: 一個具體主題實現了主題介面,除了註冊和撤銷之外,具體主題還實現了notifyObservers()方法,這個方法用來在主題狀態改變時更新所有觀察者。具體主題也可能有設定和獲取狀態的方法。
public class ConcreteSubject implements Subject
{
private final List<Observer> observers;
private float temperature;
public float getTemperature()
{
return temperature;
}
private void temperatureChanged()
{
this.notifyObservers();
}
public void setTemperature(final float temperature)
{
this.temperature = temperature;
this.temperatureChanged();
}
public ConcreteSubject()
{
observers = new ArrayList<Observer>();
}
@Override
public void registerObserver(final Observer o)
{
observers.add(o);
}
@Override
public void removeObserver(final Observer o)
{
if (observers.indexOf(o) >= 0)
{
observers.remove(o);
}
}
@Override
public void notifyObservers()
{
for (final Observer o : observers)
{
o.update(temperature);
}
}
}
客戶端使用程式碼如下:
public class Client
{
public static void main(final String[] args)
{
final ConcreteSubject sb = new ConcreteSubject();
sb.setTemperature((float) 20.00);
final Observer o = new ConcreteObserver(sb);
sb.setTemperature((float) 21.00);
}
}
三、JDK Observable
在java.util包中包含有基本的Observer介面和Observable抽象類。功能上和Subject介面和Observer介面類似.不過在使用上,就方便多了,因為許多功能比如說註冊,刪除,通知觀察者的那些功能已經內建好了。Swing程式設計中的JButton等常用控制元件均使用觀察者模式實現。
Button的處理程式碼:
JButton btn = new JButton();
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
//此處做事件處理
}
});
Button的新增程式碼:public static void main(String[] args) {
JFrame p = new JFrame();
JButton btn = new JButton("Click Me");
btn.addActionListener(new BtnListener());
p.add(btn);
p.pack();
p.setVisible(true);
}
四、推和拉
“推”的方式是指,Subject維護一份觀察者的列表,每當有更新發生,Subject會把更新訊息主動推送到各個Observer去。
“拉”的方式是指,各個Observer維護各自所關心的Subject列表,自行決定在合適的時間去Subject獲取相應的更新資料。
“推”的好處包括:
1、高效。如果沒有更新發生,不會有任何更新訊息推送的動作,即每次訊息推送都發生在確確實實的更新事件之後,都是有意義的。
2、實時。事件發生後的第一時間即可觸發通知操作。
3、可以由Subject確立通知的時間,可以避開一些繁忙時間。
4、可以表達出不同事件發生的先後順序。
“拉”的好處包括:
1、如果觀察者眾多,Subject來維護訂閱者的列表,可能困難,或者臃腫,把訂閱關係解脫到Observer去完成。
2、Observer可以不理會它不關心的變更事件,只需要去獲取自己感興趣的事件即可。
3、Observer可以自行決定獲取更新事件的時間。
4、拉的形式可以讓Subject更好地控制各個Observer每次查詢更新的訪問許可權。