java觀察者設計模式
故事:
小雪是一個非常漂亮的女孩,漂亮的女孩總是有很多的追求者,而且追求者的隊伍在不斷的變動,隨時有人進入這個隊伍,也有人退出。男孩們追求女孩時總是表現出120%的關心,當小雪私自遊玩時總是不斷收到追求者詢問小雪位置變動的訊息,小雪也不勝其煩,但小雪是如此的一個善良的女孩,她總是打斷自己正常的生活回覆男孩們的訊息。而男孩們由於要不斷的關心小雪的位置變化也弄的精疲力竭,而且還影響正常的工作。在這樣一個簡單的故事場景中我們發現了什麼?來看看小雪和男孩們的煩惱:
1.男孩們必須不斷的詢問小雪的位置變化,從而打斷正常的工作;
2.小雪也要不斷的接受男孩們的詢問,有的時候小雪的位置並沒有發生變化,還是要不斷的回覆男孩們的詢問,也影響正常的工作。
3.如果給各個男孩們回覆問題的方式都不盡相同,小雪還要知道不同的回覆方式,而且不斷的有新的男孩們增加進來,還不知道未來有什麼新的回覆方式。
看到這麼多煩惱,我們創意無限的Nokia公司給小雪和男孩們提出瞭解決方案:
Nokia公司榮譽出品了一款帶有GPRS功能的手機,該手機儲存著一個訂閱位置變化簡訊通知的電話列表,當該手機檢測到位置發生變化就會向這個訂閱列表裡的所有手機發送簡訊。看到Nokia這個解決方案,男孩們和小雪都應該鬆一口氣,他們各自都可以按照自己正常的生活習慣,只有狀態發生變化時候各自才會進行通訊。
觀察者模式還可以用生活中一個例子來表達,就是從郵局訂雜誌。假如有一個叫 妮妮 的女孩在A郵局訂了《時尚女孩》的雜誌,又在B郵局訂了《知音》雜誌,並且告訴這兩家郵局,如果雜誌到了就給我打電話我自己來拿,然後郵局就在系統中註冊下這個女孩姓名,電話等資訊。妮妮剩下的就是等郵局的電話來取雜誌了。如果雜誌到了,郵局打電話給妮妮說,您的雜誌到了,請到某某郵局來取(這相當於程式中把物件的引用——郵局名,傳給觀察者),如果只說您的雜誌到了,請到郵局來取,妮妮怎麼知道去哪個郵局拿雜誌呀。
下面的程式模仿上面的情形,一個隨機數產生物件和兩個觀察者,這兩個觀察者都在隨機數產生物件那裡註冊了,意思說如果你產生了新的數字,就通知我一聲。
結構圖:
類說明名稱 | 功能說明 |
Observer | 表示觀察者的介面,要成為觀察者必須實現此接口才行 |
NumberGenerator | 表示產生數值的抽象類 |
RandomNumberGenerator | 產生隨機數的類,繼承於NumberGenerator |
NumberObserver | 數字觀察者,會打印出變化的數字 |
SymbolObserver | 符號觀察者,列印N 個符號,列印多少個符號,由接受到的數值確定 |
1.Observer
- package com.pattern.observer;
- publicinterface Observer {
- publicabstractvoid update(NumberGenerator generator);
- }
package com.pattern.observer;
public interface Observer {
public abstract void update(NumberGenerator generator);
}
2.NumberGenerator
Java程式碼- 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 產生數值的抽象類
- */
- publicabstractclass NumberGenerator {
- private ArrayList observers = new ArrayList(); //儲存Observer
- /** 新增觀察者*/
- publicvoid addObserver(Observer observer) {
- observers.add(observer);
- }
- /** 刪除觀察者*/
- publicvoid delObserver(Observer observer) {
- observers.remove(observer);
- }
- /** 通知所有觀察者*/
- publicvoid notifyObservers() {
- Iterator it = observers.iterator();
- while(it.hasNext()) {
- Observer o =(Observer) it.next();
- o.update(this);//this相當於上面提到的郵局名
- }
- }
- publicabstractint getNumber();//獲取數字
- publicabstractvoid generate();//產生數字
- }
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
Java程式碼- 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 用於產生隨機數及通知觀察者的類
- */
- publicclass RandomNumberGenerator extends NumberGenerator{
- private Random random = new Random();//隨機數產生器
- privateint number; //用於存放數字
- publicvoid generate() {
- for(int i=0 ; i < 5; i++) {
- number = random.nextInt(10);//產生10以內的隨機數
- notifyObservers(); //有新產生的數字,通知所有註冊的觀察者
- }
- }
- /** 獲得數字*/
- publicint getNumber() {
- return number;
- }
- }
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
Java程式碼- package com.pattern.observer;
- /** 以數字表示觀察者的類*/
- publicclass NumberObserver implements Observer{
- publicvoid update(NumberGenerator generator) {
- System.out.println("NumberObserver:"+ generator.getNumber());
- try {
- Thread.sleep(1000 * 3); //為了能清楚的看到輸出,休眠3秒鐘。
- }catch(InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
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
Java程式碼- package com.pattern.observer;
- /** 以符號表示觀察者的類*/
- publicclass SymbolObserver implements Observer{
- publicvoid 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();
- }
- }
- }
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(測試類)
Java程式碼- package com.pattern.observer;
- publicclass Main {
- publicstaticvoid main(String[] args) {
- //例項化數字產生物件
- NumberGenerator generator = new RandomNumberGenerator();
- //例項化觀察者
- Observer observer1 = new NumberObserver();
- Observer observer2 = new SymbolObserver();
- //註冊觀察者
- generator.addObserver(observer1);
- generator.addObserver(observer2);
- generator.generate(); //產生數字
- }
- }
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.結果輸出
設計思想:
觀察者模式定義了物件之間的一對多的依賴關係,當一個物件的狀態發生改變時,所有它的依賴物件將被自動通知並更新