本文來自:曹勝歡博客專欄。轉載請註明出處:http://blog.csdn.net/csh624366188
Observer模式是行爲模式之一,它的作用是當一個對象的狀態發生變化時,能夠自動通知其他關聯對象,自動刷新對象狀態。Observer模式提供給關聯對象一種同步通信的手段,使某個對象與依賴它的其他對象之間保持狀態同步。《設計模式》一書對Observer是這樣描述的:定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都將得到通知並自動更新。別名:依賴(Dependents)、發佈-訂閱(Publish-Subscribe)。
下面我們就來看看觀察者模式的組成部分。
1) 抽象目標角色(Subject):目標角色知道它的觀察者,可以有任意多個觀察者觀察同一個目標。並且提供註冊和刪除觀察者對象的接口。目標角色往往由抽象類或者接口來實現。
2) 抽象觀察者角色(Observer):爲那些在目標發生改變時需要獲得通知的對象定義一個更新接口。抽象觀察者角色主要由抽象類或者接口來實現。
3)具體目標角色(Concrete Subject):將有關狀態存入各個Concrete Observer對象。當它的狀態發生改變時, 向它的各個觀察者發出通知。
4) 具體觀察者角色(Concrete Observer):存儲有關狀態,這些狀態應與目標的狀態保持一致。實現Observer的更新接口以使自身狀態與目標的狀態保持一致。在本角色內也可以維護一個指向Concrete Subject對象的引用。
結構如下:
觀察者模式的優缺點:
觀察者模式的效果有以下的優點:
第一、觀察者模式在被觀察者和觀察者之間建立一個抽象的耦合。被觀察者角色所知道的只是一個具體觀察者列表,每一個具體觀察者都符合一個抽象觀察者的接口。被觀察者並不認識任何一個具體觀察者,它只知道它們都有一個共同的接口。
由於被觀察者和觀察者沒有緊密地耦合在一起,因此它們可以屬於不同的抽象化層次。如果被觀察者和觀察者都被扔到一起,那麼這個對象必然跨越抽象化和具體化層次。
第二、觀察者模式支持廣播通訊。被觀察者會向所有的登記過的觀察者發出通知,
觀察者模式有下面的缺點:
第一、如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。
第二、如果在被觀察者之間有循環依賴的話,被觀察者會觸發它們之間進行循環調用,導致系統崩潰。在使用觀察者模式是要特別注意這一點。
第三、如果對觀察者的通知是通過另外的線程進行異步投遞的話,系統必須保證投遞是以自恰的方式進行的。
第四、雖然觀察者模式可以隨時使觀察者知道所觀察的對象發生了變化,但是觀察者模式沒有相應的機制使觀察者知道所觀察的對象是怎麼發生變化的。
下面用程序來說明一下觀察者模式的流程:
一個隨機數產生對象和兩個觀察者,這兩個觀察者都在隨機數產生對象那裏註冊了,意思說如果你產生了新的數字,就通知我一聲。
結構圖:
類說明
名稱 |
功能說明 |
Observer |
表示觀察者的接口,要成爲觀察者必須實現此接口才行 |
NumberGenerator |
表示產生數值的抽象類 |
RandomNumberGenerator |
產生隨機數的類,繼承於NumberGenerator |
NumberObserver |
數字觀察者,會打印出變化的數字 |
SymbolObserver |
符號觀察者,打印N 個符號,打印多少個符號,由接受到的數值確定 |
1.Observer
- package com.pattern.observer;
- public interface Observer {
- public abstract void update(NumberGenerator generator);
- }
2.NumberGenerator
- package com.pattern.observer;
- import java.util.ArrayList;
- import java.util.Iterator;
- /**
- * @project JavaPattern
- * @author sunnylocus
- * @verson 1.0.0
- * @date Aug 27, 2008 1:35:34 PM
- * @description 產生數值的抽象類
- */
- public abstract class NumberGenerator {
- private ArrayList observers = new ArrayList(); //存儲Observer
- /** 添加觀察者*/
- public void addObserver(Observer observer) {
- observers.add(observer);
- }
- /** 刪除觀察者*/
- public void delObserver(Observer observer) {
- observers.remove(observer);
- }
- /** 通知所有觀察者*/
- public void notifyObservers() {
- Iterator it = observers.iterator();
- while(it.hasNext()) {
- Observer o =(Observer) it.next();
- o.update(this);//this相當於上面提到的郵局名
- }
- }
- public abstract int getNumber();//獲取數字
- public abstract void generate();//產生數字
- }
3.RandomNumberGenerator
- package com.pattern.observer;
- import java.util.Random;
- /**
- * @project JavaPattern
- * @author sunnylocus
- * @verson 1.0.0
- * @date Aug 27, 2008 1:48:03 PM
- * @description 用於產生隨機數及通知觀察者的類
- */
- public class RandomNumberGenerator extends NumberGenerator{
- private Random random = new Random();//隨機數產生器
- private int number; //用於存放數字
- public void generate() {
- for(int i=0 ; i < 5; i++) {
- number = random.nextInt(10);//產生10以內的隨機數
- notifyObservers(); //有新產生的數字,通知所有註冊的觀察者
- }
- }
- /** 獲得數字*/
- public int getNumber() {
- return number;
- }
- }
4.NumberObserver
- package com.pattern.observer;
- /** 以數字表示觀察者的類*/
- public class NumberObserver implements Observer{
- public void update(NumberGenerator generator) {
- System.out.println("NumberObserver:"+ generator.getNumber());
- try {
- Thread.sleep(1000 * 3); //爲了能清楚的看到輸出,休眠3秒鐘。
- }catch(InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
5.SymbolObserver
- package com.pattern.observer;
- /** 以符號表示觀察者的類*/
- public class SymbolObserver implements Observer{
- public void update(NumberGenerator generator) {
- System.out.print("SymbolObserver:");
- int count = generator.getNumber();
- for(int i = 0 ; i < count; i ++) {
- System.out.print("*^_^* ");
- }
- System.out.println("");
- try {
- Thread.sleep(1000 * 3);
- }catch(InterruptedException e){
- e.printStackTrace();
- }
- }
- }
6.Main(測試類)
- package com.pattern.observer;
- public class Main {
- public static void main(String[] args) {
- //實例化數字產生對象
- NumberGenerator generator = new RandomNumberGenerator();
- //實例化觀察者
- Observer observer1 = new NumberObserver();
- Observer observer2 = new SymbolObserver();
- //註冊觀察者
- generator.addObserver(observer1);
- generator.addObserver(observer2);
- generator.generate(); //產生數字
- }
- }
7.結果輸出