1. 程式人生 > >觀察者模式【Observer Pattern】

觀察者模式【Observer Pattern】

     《孫子兵法》有云:“知彼知己,百戰不殆;不知彼而知己,一勝一負;不知彼,不知己,每戰必殆”,那怎麼才能知己知彼呢?知己是很容易的,自己的軍隊嘛,很容易知道,那怎麼知彼呢?安插間諜是很好的一個辦法,我們今天就來講一個間諜的故事。

韓非子大家都應該記得吧,法家的代表人物,主張建立法制社會,實施重罰制度,真是非常有遠見呀,看看現在社會在呼籲什麼,建立法制化的社會,在2000 多年前就已經提出了。大家可能還不知道,法家還有一個非常重要的代表人物,李斯,對,就是李斯,秦國的丞相,最終被殘忍的車裂的那位,李斯和韓非子都是荀子的學生,李斯是師兄,韓非子是師弟,若干年後,李斯成為最強諸侯秦國的上尉,致力於統一全國,於是安插了間諜到各個國家的重要人物的身邊,以獲取必要的資訊,韓非子作為韓國的重量級人物,身邊自然沒少間諜了,韓非子早飯吃的什麼,中午放了幾個P,晚上在做什麼娛樂,李斯都瞭如指掌,那可是相隔千里!怎麼做到的呢?間諜呀! 好,我們先通過程式把這個過程展現一下,看看李斯是怎麼監控韓非子,先看類圖:


看慣了清一色的談黃色類圖,咱換個顏色,寫程式是一個藝術創作過程,我的一個同事就曾經把一個類圖畫成一個小烏龜的形狀,超級牛X。這個類圖應該是程式設計師最容易想到得,你要監控,我就給你監控,正確呀,我們來看程式的實現,先看我們的主角韓非子的介面(類似於韓非子這樣的人,被觀察者角色):

/**
 * I'm glad to share my knowledge with you
 *         all. 類似韓非子這花樣的人,被監控起來了還不知道
 */
public interface IHanFeiZi {
	// 韓非子也是人,也要吃早飯的
	public void haveBreakfast();

	// 韓非之也是人,是人就要娛樂活動,至於活動時啥,嘿嘿,不說了
	public void haveFun();
}


然後看韓非子的實現類HanFeiZi.java:

import IHanFeiZi.IHanFeiZi;

/**
 * I'm glad to share my knowledge with you all. 韓非子,李斯的師弟,韓國的重要人物
 */
public class HanFeiZi implements IHanFeiZi {
	// 韓非子是否在吃飯,作為監控的判斷標準
	private boolean isHaveBreakfast = false;
	// 韓非子是否在娛樂
	private boolean isHaveFun = false;

	// 韓非子要吃飯了
	public void haveBreakfast() {
		System.out.println("韓非子:開始吃飯了...");
		this.isHaveBreakfast = true;
	}

	// 韓非子開始娛樂了,古代人沒啥娛樂,你能想到的就那麼多
	public void haveFun() {
		System.out.println("韓非子:開始娛樂了...");
		this.isHaveFun = true;
	}

	// 以下是bean的基本方法,getter/setter,不多說
	public boolean isHaveBreakfast() {
		return isHaveBreakfast;
	}

	public void setHaveBreakfast(boolean isHaveBreakfast) {
		this.isHaveBreakfast = isHaveBreakfast;
	}

	public boolean isHaveFun() {
		return isHaveFun;
	}

	public void setHaveFun(boolean isHaveFun) {
		this.isHaveFun = isHaveFun;
	}
}

其中有兩個getter/setter 方法,這個就沒有在類圖中表示出來,比較簡單,通過isHaveBreakfast和isHaveFun 這兩個布林型變數來判斷韓非子是否在吃飯或者娛樂,韓非子是屬於被觀察者,那還有觀察者李斯,我們來看李斯這類人的介面:
/**
 * I'm glad to share my knowledge with you all. 類似於李斯的這種人,現代嘛叫做偷窺狂
 */
public interface ILiSi {
	// 一發現別人有動靜,自己也要行動起來
	public void update(String context);
}

李斯這類人比較簡單,一發現自己觀察的物件發生了變化,比如吃飯,娛樂了,自己立刻也要行動起來,那怎麼行動呢?看實現類:
import ILiSi.ILiSi;

/**
 * I'm glad to share my knowledge with you all. 李斯這個人,是個觀察者,只要韓非子一有動靜,這邊就知道
 */
public class LiSi implements ILiSi {
	// 首先李斯是個觀察者,一旦韓非子有活動,他就知道,他就要向老闆彙報
	public void update(String str) {
		System.out.println("李斯:觀察到韓非子活動,開始向老闆彙報了...");
		this.reportToQiShiHuang(str);
		System.out.println("李斯:彙報完畢,秦老闆賞給他兩個蘿蔔吃吃...\n");
	}

	// 彙報給秦始皇
	private void reportToQiShiHuang(String reportContext) {
		System.out.println("李斯:報告,秦老闆!韓非子有活動了--->" + reportContext);
	}
}

韓非子是秦始皇非常崇拜的人物,甚至說過見韓非子一面死又何憾!不過,韓非子還真是被秦始皇幹掉的,歷史呀上演過太多這樣的悲劇。這麼重要的人物有活動,你李斯敢不向老大彙報?!兩個重量級的人物都定義出來了,那我們就來看看要怎麼監控,先寫個監控程式:
package com;

class Watch extends Thread {
	private HanFeiZi hanFeiZi;
	private LiSi liSi;
	private String type;

	// 通過建構函式傳遞引數,我要監控的是誰,誰來監控,要監控什麼
	public Watch(HanFeiZi _hanFeiZi, LiSi _liSi, String _type) {
		this.hanFeiZi = _hanFeiZi;
		this.liSi = _liSi;
		this.type = _type;
	}

	@Override
	public void run() {
		while (true) {
			if (this.type.equals("breakfast")) { // 監控是否在吃早餐
			// 如果發現韓非子在吃飯,就通知李斯
				if (this.hanFeiZi.isHaveBreakfast()) {
					this.liSi.update("韓非子在吃飯");
					// 重置狀態,繼續監控
					this.hanFeiZi.setHaveBreakfast(false);
				}
			} else {// 監控是否在娛樂
				if (this.hanFeiZi.isHaveFun()) {
					this.liSi.update("韓非子在娛樂");
					this.hanFeiZi.setHaveFun(false);
				}
			}
		}
	}
}

監控程式繼承了java.lang.Thread 類,可以同時啟動多個執行緒進行監控,Java 的多執行緒機制還是比較簡單的,繼承Thread 類,重寫run()方法,然後new SubThread(),再然後subThread.start()就可以啟動一個執行緒了,我們繼續往下看:
package com;

public class Client {
	public static void main(String[] args) throws InterruptedException {
		// 定義出韓非子和李斯
		LiSi liSi = new LiSi();
		HanFeiZi hanFeiZi = new HanFeiZi();
		// 觀察早餐
		Watch watchBreakfast = new Watch(hanFeiZi, liSi, "breakfast");
		// 開始啟動執行緒,監控
		watchBreakfast.start();
		// 觀察娛樂情況
		Watch watchFun = new Watch(hanFeiZi, liSi, "fun");
		watchFun.start();
		// 然後這裡我們看看韓非子在幹什麼
		Thread.sleep(1000); // 主執行緒等待1秒後後再往下執行
		hanFeiZi.haveBreakfast();
		// 韓非子娛樂了
		Thread.sleep(1000);
		hanFeiZi.haveFun();
	}
}

執行結果如下:


結果出來,韓非子一吃早飯李斯就知道,韓非子一娛樂李斯也知道,非常正確!結果正確但並不表示你有成績,我告訴你:你的成績是0,甚至是負的,你有沒有看到你的CPU 飆升,Eclipse 不響應狀態?看到了?看到了你還不想為什麼?!看看上面的程式,別的就不多說了,使用了一個while(true)這樣一個死迴圈來做監聽,你要是用到專案中,你要多少硬體投入進來?你還讓不讓別人的程式也run 起來?!一臺伺服器就跑你這一個程式就完事了,錯,絕對的錯!
錯誤也看到了,我們必須要修改,這個沒有辦法應用到專案中去呀,而且這個程式根本就不是面向物件的程式,這完全是面向過程的(我寫出這樣的程式也不容易呀,安慰一下自己),不改不行,怎麼修改呢?我們來想,既然韓非子一吃飯李斯就知道了,那我們為什麼不把李斯這個類聚集到韓非子這裡類上呢?說改就改,立馬動手,我們來看修改後的類圖:


類圖非常簡單,就是在HanFeiZi 類中引用了IliSi 這個介面,看我們程式程式碼怎麼修改,IhanFeiZi介面完全沒有修改,我們來看HanFeiZi 這個實現類:

package com;

/**
 * I'm glad to share my knowledge with you all. 韓非子,李斯的師弟,韓國的重要人物
 */
public class HanFeiZi implements IHanFeiZi {
	// 把李斯宣告出來
	private ILiSi liSi = new LiSi();

	// 韓非子要吃飯了
	public void haveBreakfast() {
		System.out.println("韓非子:開始吃飯了...");
		// 通知李斯
		this.liSi.update("韓非子在吃飯");
	}

	// 韓非子開始娛樂了,古代人沒啥娛樂,你能想到的就那麼多
	public void haveFun() {
		System.out.println("韓非子:開始娛樂了...");
		this.liSi.update("韓非子在娛樂");
	}
}


韓非子HanFeiZi 實現類就把介面的兩個方法實現就可以了,在每個方法中呼叫LiSi.update()方法,完成李斯觀察韓非子任務,李斯的介面和實現類都沒有任何改變,我們再來看看Client 程式的變更:

package com;

/**
 * @author cbf4Life [email protected] I'm glad to share my knowledge with you
 *         all. 這個Client就是我們,用我們的視角看待這段歷史
 */
public class Client {
	public static void main(String[] args) {
		// 定義出韓非子
		HanFeiZi hanFeiZi = new HanFeiZi();
		// 然後這裡我們看看韓非子在幹什麼
		hanFeiZi.haveBreakfast();
		// 韓非子娛樂了
		hanFeiZi.haveFun();
	}
}

李斯都不用在Client 中定義了,非常簡單,執行結果如下:


執行結果正確,效率也比較高,是不是應該樂呵樂呵了?大功告成了?稍等等,你想在戰國爭雄的時候,韓非子這麼有名望(法家代表)、有實力(韓國的公子,他老爹參與過爭奪韓國王位)的人,就只有秦國一個國家關心他嗎?想想也不可能呀,肯定有一大幫的各國的類似李斯這樣的人在看著他,監視著一舉
一動,但是看看我們的程式,你在HanFeiZi 這個類中定義:

private ILiSi liSi =new LiSi();


一下子就敲死了,只有李斯才能觀察到韓非子,這是不對的,也就是說韓非子的活動只通知了李斯一個人,這不可能;再者,李斯只觀察韓非子的吃飯,娛樂嗎?政治傾向不關心嗎?思維傾向不關心嗎?殺人放火不關心嗎?也就說韓非子的一系列活動都要通知李斯,那可怎麼辦?要按照上面的例子,我們不是要修改瘋掉了嗎?這和開閉原則嚴重違背呀,我們的程式有問題,怎麼修改,來看類圖:


我們把介面名稱修改了一下,這樣顯得更抽象化,Observable 是被觀察者,就是類似韓非子這樣的人,Observer 介面是觀察者,類似李斯這樣的,同時還有其他國家的比如王斯、劉斯等,在Observable 介面中有三個比較重要的方法,分別是addObserver 增加觀察者,deleteObserver 刪除觀察者,notifyObservers通知所有的觀察者,這是什麼意思呢?我這裡有一個資訊,一個物件,我可以允許有多個物件來察看,你觀察也成,我觀察也成,只要是觀察者就成,也就是說我的改變或動作執行,會通知其他的物件,看程式會更明白一點,先看Observable 介面:

package com;

import java.util.Observer;

/**
 * I'm glad to share my knowledge with you all. 所有被觀察者者,通用介面
 */
public interface Observable {
	// 增加一個觀察者
	public void addObserver(Observer observer);

	// 刪除一個觀察者,——我不想讓你看了
	public void deleteObserver(Observer observer);

	// 既然要觀察,我發生改變了他也應該用所動作——通知觀察者
	public void notifyObservers(String context);
}

這是一個通用的被觀察者介面,所有的被觀察者都可以實現這個介面。再來看韓非子的實現類:
package com;

import java.util.ArrayList;
import java.util.Observer;

/**
 * I'm glad to share my knowledge with you all. 韓非子,李斯的師弟,韓國的重要人物
 */
public class HanFeiZi implements Observable {
	// 定義個變長陣列,存放所有的觀察者
	private ArrayList<Observer> observerList = new ArrayList<Observer>();

	// 增加觀察者
	public void addObserver(Observer observer) {
		this.observerList.add(observer);
	}

	// 刪除觀察者
	public void deleteObserver(Observer observer) {
		this.observerList.remove(observer);
	}

	// 通知所有的觀察者
	public void notifyObservers(String context) {
		for (Observer observer : observerList) {
			observer.update(context);
		}
	}

	// 韓非子要吃飯了
	public void haveBreakfast() {
		System.out.println("韓非子:開始吃飯了...");
		// 通知所有的觀察者
		this.notifyObservers("韓非子在吃飯");
	}

	// 韓非子開始娛樂了,古代人沒啥娛樂,你能想到的就那麼多
	public void haveFun() {
		System.out.println("韓非子:開始娛樂了...");
		this.notifyObservers("韓非子在娛樂");
	}
}

再來看觀察者介面Observer.java:
package com;

/**
 * I'm glad to share my knowledge with you all. 所有觀察者,通用介面
 */
public interface Observer {
	// 一發現別人有動靜,自己也要行動起來
	public void update(String context);
}


然後是三個很無恥的觀察者,偷窺狂嘛:

package com;

/**
 * I'm glad to share my knowledge with you all. 李斯這個人,是個觀察者,只要韓非子一有動靜,這邊就知道
 */
public class LiSi implements Observer {
	// 首先李斯是個觀察者,一旦韓非子有活動,他就知道,他就要向老闆彙報
	public void update(String str) {
		System.out.println("李斯:觀察到李斯活動,開始向老闆彙報了...");
		this.reportToQiShiHuang(str);
		System.out.println("李斯:彙報完畢,秦老闆賞給他兩個蘿蔔吃吃...\n");
	}

	// 彙報給秦始皇
	private void reportToQiShiHuang(String reportContext) {
		System.out.println("李斯:報告,秦老闆!韓非子有活動了--->" + reportContext);
	}
}

李斯是真有其人,以下兩個觀察者是杜撰出來的:
package com;

/**
 * I'm glad to share my knowledge with you all. 王斯,也是觀察者,杜撰的人名
 */
public class WangSi implements Observer {
	// 王斯,看到韓非子有活動,自己就受不了
	public void update(String str) {
		System.out.println("王斯:觀察到韓非子活動,自己也開始活動了...");
		this.cry(str);
		System.out.println("王斯:真真的哭死了...\n");
	}

	// 一看李斯有活動,就哭,痛哭
	private void cry(String context) {
		System.out.println("王斯:因為" + context + ",——所以我悲傷呀!");
	}
}


package com;

/**
 * I'm glad to share my knowledge with you
 *         all. 劉斯這個人,是個觀察者,只要韓非子一有動靜,這邊就知道 杜撰的人名 
 */
public class LiuSi implements Observer {
	// 劉斯,觀察到韓非子活動後,自己也做一定得事情
	public void update(String str) {
		System.out.println("劉斯:觀察到韓非子活動,開始動作了...");
		this.happy(str);
		System.out.println("劉斯:真被樂死了\n");
	}

	// 一看韓非子有變化,他就快樂
	private void happy(String context) {
		System.out.println("劉斯:因為" + context + ",——所以我快樂呀!");
	}
}

所有的歷史人物都在場了,那我們來看看這場歷史鬧劇是如何演繹的:
package com;

/**
 * I'm glad to share my knowledge with you all. 這個Client就是我們,用我們的視角看待這段歷史
 */
public class Client {
	public static void main(String[] args) {
		// 三個觀察者產生出來
		Observer liSi = new LiSi();
		Observer wangSi = new WangSi();
		Observer liuSi = new LiuSi();
		// 定義出韓非子
		HanFeiZi hanFeiZi = new HanFeiZi();
		// 我們後人根據歷史,描述這個場景,有三個人在觀察韓非子
		hanFeiZi.addObserver(liSi);
		hanFeiZi.addObserver(wangSi);
		hanFeiZi.addObserver(liuSi);
		// 然後這裡我們看看韓非子在幹什麼
		hanFeiZi.haveBreakfast();
	}
}

執行結果如下:


    好了,結果也正確了,也符合開閉原則了,也同時實現類間解耦,想再加觀察者?好呀,繼續實現Observer 介面就成了,這時候必須修改Client 程式,因為你業務都發生了變化。
細心的你可能已經發現,HanFeiZi 這個實現類中應該抽象出一個父類,父類完全實現介面,HanFeiZi這個類只實現兩個方法haveBreakfast 和haveFun 就可以了,是的,是的,確實是應該這樣,那先稍等等,我們開啟JDK 的幫助檔案看看,查詢一下Observable 是不是已經有這個類了? JDK 中提供了:java.util.Observable 實現類和java.util.Observer 介面,也就是說我們上面寫的那個例子中的Observable 介面可以改換成java.util.Observale 實現類了,看如下類圖:


是不是又簡單了很多?那就對了!然後我們看一下我們程式的變更,先看HanFeiZi 的實現類:

package com;

import java.util.ArrayList;
import java.util.Observable;

/**
 * I'm glad to share my knowledge with you
 *         all. 韓非子,李斯的師弟,韓國的重要人物
 */
public class HanFeiZi extends Observable {
	// 韓非子要吃飯了
	public void haveBreakfast() {
		System.out.println("韓非子:開始吃飯了...");
		// 通知所有的觀察者
		super.setChanged();
		super.notifyObservers("韓非子在吃飯");
	}

	// 韓非子開始娛樂了,古代人沒啥娛樂,你能想到的就那麼多
	public void haveFun() {
		System.out.println("韓非子:開始娛樂了...");
		super.setChanged();
		this.notifyObservers("韓非子在娛樂");
	}
}

    改變的不多,引入了一個java.util.Observable 物件,刪除了增加、刪除觀察者的方法,簡單了很多,
那我們再來看觀察者的實現類:
package com;

import java.util.Observable;
import java.util.Observer;

/**
 * I'm glad to share my knowledge with you all. 李斯這個人,是個觀察者,只要韓非子一有動靜,這邊就知道
 */
public class LiSi implements Observer {
	// 首先李斯是個觀察者,一旦韓非子有活動,他就知道,他就要向老闆彙報
	public void update(<span style="background-color: rgb(255, 255, 102);">Observable observable, Object obj</span>) {
		System.out.println("李斯:觀察到李斯活動,開始向老闆彙報了...");
		this.reportToQiShiHuang(<span style="background-color: rgb(255, 255, 51);">obj.toString()</span>);
		System.out.println("李斯:彙報完畢,秦老闆賞給他兩個蘿蔔吃吃...\n");
	}

	// 彙報給秦始皇
	private void reportToQiShiHuang(String reportContext) {
		System.out.println("李斯:報告,秦老闆!韓非子有活動了--->" + reportContext);
	}
}


就改變了黃色的部分,應該java.util.Observer 介面要求update 傳遞過來兩個變數,Observable 這個變數我們沒用到,就不處理了。其他兩個觀察者實現類也是相同的改動,如下程式碼:

package com;

import java.util.Observable;
import java.util.Observer;

/**
 * I'm glad to share my knowledge with you all. 王斯,也是觀察者,杜撰的人名
 */
public class WangSi implements Observer {
	// 王斯,看到韓非子有活動,自己就受不了
	public void update(Observable observable, Object obj) {
		System.out.println("王斯:觀察到韓非子活動,自己也開始活動了...");
		this.cry(obj.toString());
		System.out.println("王斯:真真的哭死了...\n");
	}

	// 一看李斯有活動,就哭,痛哭
	private void cry(String context) {
		System.out.println("王斯:因為" + context + ",——所以我悲傷呀!");
	}
}

package com;

import java.util.Observable;
import java.util.Observer;

/**
 * I'm glad to share my knowledge with you all. 劉斯這個人,是個觀察者,只要韓非子一有動靜,這邊就知道
 * 杜撰的人名
 */
public class LiuSi implements Observer {
	// 劉斯,觀察到韓非子活動後,自己也做一定得事情
	public void update(Observable observable, Object obj) {
		System.out.println("劉斯:觀察到韓非子活動,開始動作了...");
		this.happy(obj.toString());
		System.out.println("劉斯:真被樂死了\n");
	}

	// 一看韓非子有變化,他就快樂
	private void happy(String context) {
		System.out.println("劉斯:因為" + context + ",——所以我快樂呀!");
	}
}

然後再來看Client 程式:
package com;

import java.util.Observer;

/**
 * I'm glad to share my knowledge with you all. 這個Client就是我們,用我們的視角看待這段歷史
 */
public class Client {
	public static void main(String[] args) {
		// 三個觀察者產生出來
		Observer liSi = new LiSi();
		Observer wangSi = new WangSi();
		Observer liuSi = new LiuSi();
		// 定義出韓非子
		HanFeiZi hanFeiZi = new HanFeiZi();
		// 我們後人根據歷史,描述這個場景,有三個人在觀察韓非子
		hanFeiZi.addObserver(liSi);
		hanFeiZi.addObserver(wangSi);
		hanFeiZi.addObserver(liuSi);
		// 然後這裡我們看看韓非子在幹什麼
		hanFeiZi.haveBreakfast();
	}
}

程式體內沒有任何變更,只是引入了一個介面而已,執行結果如下:


執行結果一樣,只是通知的先後順序不同而已,程式已經簡約到極致了。
以上講解的就是觀察者模式,這個模式的通用類圖如下:


觀察者模式在實際專案的應用中非常常見,比如你到ATM 機器上取錢,多次輸錯密碼,卡就會被ATM吞掉,吞卡動作發生的時候,會觸發哪些事件呢?第一攝像頭連續快拍,第二,通知監控系統,吞卡發生;第三,初始化ATM 機螢幕,返回最初狀態,你不能因為就吞了一張卡,整個ATM 都不能用了吧,一般前兩個動作都是通過觀察者模式來完成的。
觀察者模式有一個變種叫做釋出/訂閱模型(Publish/Subscribe),如果你做過EJB(EnterpriseJavaBean)的開發,這個你絕對不會陌生。EJB2 是個折騰死人不償命的玩意兒,寫個Bean 要實現,還要繼承,再加上那一堆的配置檔案,小專案還湊活,你要知道用EJB 開發的基本上都不是小專案,到最後是每個專案成員都在罵EJB 這個忽悠人的東西;但是EJB3 是個非常優秀的框架,還是算比較輕量級,寫個Bean只要加個Annotaion 就成了,配置檔案減少了,而且也引入了依賴注入的概念,雖然只是EJB2 的翻版,但是畢竟還是前進了一步,不知道以後EJB 的路會怎麼樣。在EJB 中有三個型別的Bean: Session Bean、EntityBean 和MessageDriven Bean,我們這裡來說一下MessageDriven Bean(一般簡稱為MDB),訊息驅動Bean,訊息的釋出者(Provider)釋出一個訊息,也就是一個訊息驅動Bean,通過EJB 容器(一般是Message Queue訊息佇列)通知訂閱者做出迴應,從原理上看很簡單,就是觀察者模式的升級版。那觀察者模式在什麼情況下使用呢?觀察者可以實現訊息的廣播,一個訊息可以觸發多個事件,這是觀察者模式非常重要的功能。使用觀察者模式也有兩個重點問題要解決:廣播鏈的問題。如果你做過資料庫的觸發器,你就應該知道有一個觸發器鏈的問題,比如表A 上寫了一個觸發器,內容是一個欄位更新後更新表B 的一條資料,而表B 上也有個觸發器,要更新表C,表C 也有觸發器…,完蛋了,這個資料庫基本上就毀掉了!我們的觀察者模式也是一樣的問題,一個觀察者可以有雙
重身份,即使觀察者,也是被觀察者,這沒什麼問題呀,但是鏈一旦建立,這個邏輯就比較複雜,可維護
性非常差,根據經驗建議,在一個觀察者模式中最多出現一個物件既是觀察者也是被觀察者,也就是說消
息最多轉發一次(傳遞兩次),這還是比較好控制的;
非同步處理問題。這個EJB 是一個非常好的例子,被觀察者發生動作了,觀察者要做出迴應,如果觀察
者比較多,而且處理時間比較長怎麼辦?那就用非同步唄,非同步處理就要考慮執行緒安全和佇列的問題,這個
大家有時間看看Message Queue,就會有更深的瞭解。

我們在來回顧一下我們寫的程式,觀察者增加了,我就必須修改業務邏輯Client 程式,這個是必須得
嗎?回顧一下我們以前講到工廠方法模式的時候用到了ClassUtils 這個類,其中有一個方法就是根據介面
查詢到所有的實現類,問題解決了吧!我可以查詢到所有的觀察者,然後全部加進來,以後要是新增加觀
察者也沒有問題呀,程式那真是一點都不用改了!

相關推薦

觀察模式Observer Pattern

     《孫子兵法》有云:“知彼知己,百戰不殆;不知彼而知己,一勝一負;不知彼,不知己,每戰必殆”,那怎麼才能知己知彼呢?知己是很容易的,自己的軍隊嘛,很容易知道,那怎麼知彼呢?安插間諜是很好的一個辦法,我們今天就來講一個間諜的故事。 韓非子大家都應該記得吧,法家的代表人

C#設計模式之十六觀察模式Observer Pattern行為型

ngx 現實生活 松耦合 mon html 機制 account current 很好 原文:C#設計模式之十六觀察者模式(Observer Pattern)【行為型】一、引言 今天是2017年11月份的最後一天,也就是2017年11月30日,利用今天再寫一個模式,爭取

C#設計模式(17)——觀察模式Observer Pattern

oid tar 自然 img info handler 這不 自身 dash 原文:C#設計模式(17)——觀察者模式(Observer Pattern)一、引言   在現實生活中,處處可見觀察者模式,例如,微信中的訂閱號,訂閱博客和QQ微博中關註好友,這些都屬於觀察者

觀察模式Observer Pattern

servers his add pattern 一個 玩家 name list turn 觀察者模式又叫做訂閱/發布模式 一個Subject,多Observer 相互之間持有引用 Subject可以調用Observer的函數執行相應操作 Observer發生變動時也可以通

設計模式----觀察模式 含例項

日常學習C++設計模式中... 給自己留個備份,有問題歡迎溝通交流。 好了,開始嘍~ --------------------------------------------------------------------------------------------------

觀察模式Observer Pattern)。

定義 觀察者模式也叫做釋出訂閱模式(Publish/subscribe),他是一個在專案中經常使用的模式,其定義如下: 定義物件間一種一對多的依賴關係,使得每當一個物件改變狀態,則所有依賴於他的物件都會得到通知並被自動更新。 我們現來解釋一下觀察者模式的幾個角色名稱:

設計模式觀察模式Observer Pattern

目錄 一、模式含義 觀察者模式(Observer Pattern):定義物件之間的一種一對多依賴關係,使得每當一個物件狀態發生改變時,其相關依賴物件皆得到通知並被自動更新。 觀察者模式的別名:包括釋出-訂閱(Publi

建立型模式--建造模式Builder Pattern

介紹 建造者模式使用多個簡單的物件一步一步構建成一個複雜的物件。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。 原始碼 java.lang.StringBuilder#appe

Java 設計模式——觀察模式Observer Pattern

    前言 一、簡介 二、實現步驟 (1)實現方式: (2)舉例: (3)步驟簡化版: 三、程式碼實現 四、總結 五、Demo地址 六、參考文件 七、內容推薦 前言 本來沒想寫前言的,感覺就是一堆廢話。那就當

設計模式觀察模式Observer Pattern

觀察者模式 觀察者模式定義了物件之間的一對多依賴,這樣一來,當一個物件改變狀態時,它的所有依賴者都會收到通知並自動更新 在觀察者模式中,發生改變的物件稱為觀察目標,而被通知的物件稱為觀察者,一個觀察目標可以對應多個觀察者。一個軟體系統常常要求在某一個物件的狀

觀察模式Observer Pattern,物件行為型模式,釋出-訂閱模式 Publish/Subscribe Pattern

意圖 通知狀態變化 定義物件間的一對多的依賴關係,當一個物件的狀態發生變化時,所有依賴它的物件都得到通知並被自動更新,由抽象類或介面實現。 推模式:目標角色複雜,並且觀察者角色進行更行時必須得到一些具體的變化資訊 拉模式:目標角色簡單 適用性 在

Java設計模式觀察模式Observer Pattern

觀察者模式:類似於報紙和雜誌的訂閱 出版者+訂閱者=觀察者模式 1.報紙的業務就是出版報紙。 2.向某家報社訂閱報紙,只要他們有新報紙出版,就會給你送來。只要你是他們的訂閱使用者,你就會一直收到新報紙。 3.當你不想再看報紙時,取消訂閱,他們就不會再

Unity遊戲設計模式(二)觀察模式Observer Pattern

        最近看遊戲設計模式,當看到觀察者模式時被搞得雲裡霧裡的,什麼觀察者,被觀察者,抽象觀察者,抽象被觀察者。聽著這些詞就覺得可怕,其實理解以後還是比較簡單的。         當我們玩遊戲時,經常會出現一些事件,而這個事件可能會影響到許多個模組時就可以用到觀察者

Head First設計模式觀察模式Observer Pattern

前言:     這一節開始學習觀察者模式,開始講之前會先像第一節那樣通過一個應用場景來引入該模式。具體場景為:氣象站提供了一個WeatherData物件,該物件可以追蹤獲取天氣的溫度、氣壓、溼度資訊,WeatherData物件會隨即更新三個佈告板的顯示:目前狀況(溫度、溼度、

Java設計模式——觀察模式Observer Pattern

場景一 描述:《孫子兵法》有云:“知彼知己,百戰不殆;不知彼而知己,一勝一負;不 知彼,不知己,每戰必殆”,那怎麼才能知己知彼呢?知己是很容易的,自己的軍隊嘛,很容易知道,那怎麼知彼呢?安插間諜是很

設計模式觀察模式Observer Pattern、JDK實現)

import java.util.Observable; import java.util.Observer; /** * 觀察者模式(JDK實現)。 * @author Bright Lee */ public class JdkObserverPattern { public st

Java設計模式--裝飾模式Decorator Pattern

      有時,你想要在程式執行期間為某個物件組合新的行為,且在某種情況下,你需要物件的行為發生一些細小的變化,並且這些變化可以自由組合。這時,裝飾者模式就可以滿足這種需求。  所謂裝飾者模式,也叫修飾者模式、裝飾器模式,意圖是在執行時組合操作的新變化,即動態地給一個物件

C#設計模式(4)——觀察模式Observer Pattern

一、引言    在現實生活中,處處可見觀察者模式,例如,微信中的訂閱號,訂閱部落格和QQ微博中關注好友,這些都屬於觀察者模式的應用。在這一章將分享我對觀察者模式的理解,廢話不多說了,直接進入今天的主題。 二、 觀察者模式的介紹 2.1 觀察者模式的定義   從生活

設計模式學習總結:觀察模式Observer Pattern

意圖 定義物件間的一種一對多的依賴關係,當一個物件的狀態發生變化時,所以依賴於它的物件都得到通知並被自動更新。 適用性 當一個抽象物件有兩個方面,其中一個方面依賴於另一個方面。將這兩者封裝在兩個獨立的物件中使它們可以被獨立地改變與複用。 當對一個物件

觀察模式行為模式

class call nts mat 依賴關系 接口 lis 通知 觀察 觀察者模式 Define a one-to-many dependency between objects so that when one object change state, all its