觀察者模式-Observer

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

 

1. 本身手工建立Observer模式java

首先,建立觀察者接口:安全

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 }
複製代碼

實現類:ide

複製代碼
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

this is operation
observer 1 receive
observer 2 receive

 

2. 使用java.util.Observer接口spa

這個接口只定義了一個方法: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

優勢:

  第1、觀察者模式在被觀察者和觀察者之間創建一個抽象的耦合。被觀察者角色所知道的只是一個具體觀察者列表,每個具體觀察者都符合一個抽象觀察者的接口。被觀察者並不認識任何一個具體觀察者,它只知道它們都有一個共同的接口。 因爲被觀察者和觀察者沒有緊密地耦合在一塊兒,所以它們能夠屬於不一樣的抽象化層次。 
  第2、觀察者模式支持廣播通信。被觀察者會向全部的登記過的觀察者發出通知

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

相關文章
相關標籤/搜索