觀察者模式-Observer


觀察者模式很好理解,簡單來說就是:當一個對象變化時,其它依賴該對象的對象都會收到通知,並且隨着變化!對象之間是一種一對多的關系。

 

1. 自己手工創建Observer模式

首先,創建觀察者接口:

1 public interface Observer {
2     void update();
3 }

Publisher接口:

1 public interface Publisher {
2     void add(Observer observer);
3 
4     void delete(Observer observer);
5 
6     void notifyObservers();
7 
8     void operation();
9 }

基本功能實現(為了線程安全我們可以選擇Vector):

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public abstract class PublisherAdapter implements Publisher {
 5     private List<Observer> observers = new ArrayList<Observer>();
 6 
 7     @Override
 8     public void add(Observer observer) {
 9         observers.add(observer);
10     }
11 
12     @Override
13     public void delete(Observer observer) {
14         observers.remove(observer);
15     }
16 
17     @Override
18     public void notifyObservers() {
19         for (Observer observer : observers)
20             observer.update();
21     }
22 
23 }

實現類:

1 public class PublisherImpl extends PublisherAdapter {
2 
3     @Override
4     public void operation() {
5         System.out.println("this is operation");
6         notifyObservers();
7     }
8 
9 }

測試類:

 1 public class Main {
 2 
 3     public static void main(String[] args) {
 4         Publisher impl = new PublisherImpl();
 5         impl.add(new Observer() {
 6             
 7             @Override
 8             public void update() {
 9                 System.out.println("observer 1 receive");
10             }
11         });
12         impl.add(new Observer() {
13             
14             @Override
15             public void update() {
16                 // TODO Auto-generated method stub
17                 System.out.println("observer 2 receive");
18             }
19         });
20         impl.operation();
21     }
22 
23 }

測試結果:

this is operation
observer 1 receive
observer 2 receive

 

2. 使用java.util.Observer接口

這個接口只定義了一個方法:update()。當被觀察者(observable)對象的狀態發生變化時,這個方法就會被調用。通過調用被觀察者對象的notifyObservers()方法通知所有的觀察對象。

可以定義被觀察者:

1 import java.util.Observable;
2 
3 public class Publisher extends Observable {
4     public void operation() {
5         System.out.println("this is operation");
6         this.setChanged();
7         this.notifyObservers();
8     }
9 }

則測試方法為:

 1 import java.util.Observable;
 2 import java.util.Observer;
 3 
 4 public class Main {
 5 
 6     public static void main(String[] args) {
 7         Publisher publisher = new Publisher();
 8         publisher.addObserver(new Observer() {
 9 
10             @Override
11             public void update(Observable o, Object arg) {
12                 System.out.println("observer 1 receive");
13             }
14         });
15         publisher.addObserver(new Observer() {
16 
17             @Override
18             public void update(Observable o, Object arg) {
19                 System.out.println("observer 2 receive");
20             }
21         });
22         publisher.operation();
23     }
24 
25 }

當然,若要獲得被觀察者的信息,可以將Observable o轉換為Publisher類型:

Publisher p = (Publisher)o;

 

3. 分析Observer與Observable

如前所述,Observer接口只定義了一個方法:update()。當被觀察者對象的狀態發生變化時,這個方法就會被調用。java.util.Observer接口定義如下:

1 package java.util;
2 
3 public interface Observer {
4     void update(Observable o, Object arg);
5 }

 

被觀察者類都是java.util.Observable類的子類。java.util.Observable提供公開的方法支持觀察者對象,這些方法中有兩個非常重要:一個是setChanged(),被調用之后會設置一個內部標記變量,代表被觀察者對象的狀態發生了變化;另一個是notifyObservers(),這個方法被調用時,會調用所有登記過的觀察者對象的update()方法。

 1 package java.util;
 2 
 3 public class Observable {
 4     private boolean changed = false;
 5     private Vector obs;
 6 
 7     public Observable() {
 8         obs = new Vector();
 9     }
10 
11     public synchronized void addObserver(Observer o) {
12         if (o == null)
13             throw new NullPointerException();
14         if (!obs.contains(o)) {
15             obs.addElement(o);
16         }
17     }
18 
19     public synchronized void deleteObserver(Observer o) {
20         obs.removeElement(o);
21     }
22 
23     public void notifyObservers() {
24         notifyObservers(null);
25     }
26 
27     public void notifyObservers(Object arg) {
28         Object[] arrLocal;
29 
30         synchronized (this) {
31             if (!changed)
32                 return;
33             arrLocal = obs.toArray();
34             clearChanged();
35         }
36 
37         for (int i = arrLocal.length-1; i >= 0; i--)
38             ((Observer)arrLocal[i]).update(this, arg);
39     }
40 
41     public synchronized void deleteObservers() {
42         obs.removeAllElements();
43     }
44 
45     protected synchronized void setChanged() {
46         changed = true;
47     }
48 
49     protected synchronized void clearChanged() {
50         changed = false;
51     }
52 
53     public synchronized boolean hasChanged() {
54         return changed;
55     }
56 
57     public synchronized int countObservers() {
58         return obs.size();
59     }
60 }

 

可用如下類圖表示(圖片來自於網絡):

一個Observable類代表一個被觀察者對象。一個被觀察者對象可以有多個觀察者,一個觀察者是一個實現Observer接口的對象。在被觀察者對象發生變化時,它會調用notifyObservers方法,此方法再調用所有觀察者的update()方法。

同時,發通知的順序在這里並沒有指明。Observerable類所提供的缺省實現會按照Observers對象被登記的次序通知它們(遍歷Vector),當然,我們可以在子類中改變這一次序。子類還可以在單獨的線程里通知觀察者對象、或者在一個公用的線程里按照次序執行。

當一個可觀察者對象剛剛創立時,它的觀察者集合是空的。兩個觀察者對象在它們的equals()方法返回true時,被認為是兩個相等的對象。

 

4. 觀察者模式總結

來自於:http://www.cnblogs.com/forlina/archive/2011/06/23/2088121.html

優點:

  第一、觀察者模式在被觀察者和觀察者之間建立一個抽象的耦合。被觀察者角色所知道的只是一個具體觀察者列表,每一個具體觀察者都符合一個抽象觀察者的接口。被觀察者並不認識任何一個具體觀察者,它只知道它們都有一個共同的接口。 由於被觀察者和觀察者沒有緊密地耦合在一起,因此它們可以屬於不同的抽象化層次。
  第二、觀察者模式支持廣播通訊。被觀察者會向所有的登記過的觀察者發出通知

缺點:
  第一、如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。
  第二、如果在被觀察者之間有循環依賴的話,被觀察者會觸發它們之間進行循環調用,導致系統崩潰。在使用觀察者模式是要特別注意這一點。
  第三、如果對觀察者的通知是通過另外的線程進行異步投遞的話,系統必須保證投遞是以自恰的方式進行的。
  第四、雖然觀察者模式可以隨時使觀察者知道所觀察的對象發生了變化,但是觀察者模式沒有相應的機制使觀察者知道所觀察的對象是怎么發生變化的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM