問題引入java
生成一個公告板顯示當時的天氣情況,當天氣情況發生改變的時候公告板能夠實時的更新。
編程
模式定義ide
定義對象之間的一對多的依賴,當一個對象改變狀態時,它的全部依賴者都會自動收到通知並自動更新。this
認識模式spa
該模式在生活中是很常見的。想一想生活中的各類各樣的檢測系統,報警系統,一旦有重要事件發生時,有關係統總能及時的收到通知,這就是觀察者模式。
.net
問題解決code
關於觀察者模式,java實際上給了咱們內置的支持(能夠看出該模式仍是很經常使用的吧!)可是咱們常常會本身實現。爲何呢?咱們後面會給出答案。
orm
被觀察者咱們稱之爲主題(Subject),相應的有觀察者(Observer)。
server
1、自定義實現對象
1) Subject,Observer咱們都定義爲接口
package my.oschina.net.design.observer.owndesign; public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObserver(); } public interface Observer { void update(Subject sub); }
2)實現Subject和Observer接口(主題與觀察者的實現)
a)主題實現
package my.oschina.net.design.observer.finaldesign; import java.util.ArrayList; public class WeatherData implements Subject{ //被觀測的指標數據 private float temp; private float humidity; private float pressure; //維護一個訂閱過的Observer列表 private ArrayList<Observer> Observers; public WeatherData() { this.Observers = new ArrayList<Observer>(); } @Override //增長Observer public void registerObserver(Observer o) { // TODO Auto-generated method stub Observers.add(o); } @Override //移除部分Observer public void removeObserver(Observer o) { // TODO Auto-generated method stub int i = Observers.indexOf(o); if(i != -1) Observers.remove(Observers.indexOf(o)); } @Override //通知訂閱過的Observer public void notifyObserver() { // TODO Auto-generated method stub for(Observer o : Observers) { o.update(this); } } public void setStatus(float temp, float humidity, float pressure) { this.temp = temp; this.humidity = humidity; this.pressure = pressure; statusChanged(); } public void statusChanged() { notifyObserver(); } float getTemp() { return temp; } float getHumidity() { return humidity; } float getPressure() { return pressure; } }
b)觀察者實現
package my.oschina.net.design.observer.finaldesign; public class CurrentConditionDisplay implements Observer,Display{ //接收被觀測者發過來的數據 private float temp; private float humidity; private float pressure; //保存這個主題對象,可能後續有退訂的需求 private WeatherData weatherData; public CurrentConditionDisplay(WeatherData weahterdata) { this.weatherData = weahterdata; weatherData.registerObserver(this); } @Override public void update(Subject sub) { // TODO Auto-generated method stub if(sub instanceof WeatherData) { WeatherData weatherdata = (WeatherData)sub; this.temp = weatherdata.getTemp(); this.humidity = weatherdata.getHumidity(); this.pressure = weatherdata.getPressure(); } display(); } @Override public void display() { // TODO Auto-generated method stub System.out.println("Temp --> " + temp + "humidity --> " +humidity + "pressure -->" + pressure); } }
3)Test一下
package my.oschina.net.design.observer.finaldesign; public class ObserverTest1 { public static void main(String[] args) { // TODO Auto-generated method stub WeatherData weatherdata = new WeatherData(); CurrentConditionDisplay cc = new CurrentConditionDisplay(weatherdata); weatherdata.setStatus(12, 12, 12); weatherdata.setStatus(13, 13, 13); weatherdata.setStatus(14, 14, 14); } }
4)結果截圖
2、java內置實現
在java的java.util 包(pac1kage)中包含了最基本的Observable類(可觀察,經過繼承方式得到其方法和屬性)和Observer接口(觀察),對你沒有看錯,我也沒有寫錯,的確是Observable類和Observer接口,他們相似與咱們上述本身定義的Subject和Observer接口,因爲是java內置,有的時候使用它們的話真的是挺簡單的,由於有好多的功能java自己已經爲咱們寫好了!
其實這裏你已經能夠明白這種內置實現的弊端了,對就是由於Observable是個類!在java中只支持單繼承,因此啊,這就限制了繼承他的類使用的靈活性!
java內置的不一樣
a)關於主題對象
當咱們自定義觀察者的時候當須要通知觀察者的時候咱們直接調用notifyO不servers()方法便可, 可是java內置的方法不是這樣的,咱們須要兩步走:
1>調用setChanged()方法,標記狀態已改變;
2>調用notifyObserver()方法,完成通知的工做。
深刻-------->setChanged()
咱們來看看Observable內部的實現
setChanged() { cahnged = true; } notifyObservers(Object arg) { if(cahnged) { for every obsrver on the list { call update(this, arg) } cahngd = false; } } notifyObservers() { notifyObservers(null) }
看到這裏有人可能要問了:爲何要設置一個標誌呢???仔細想一想,假設你是公司老總,天天要批一系列文件,好了,如今祕書送來一份文件你批了,一分鐘沒到,又有新的文件產生了,祕書又送了過來,而後。。。而後。。。你受得了嗎?你可能會對祕書說:小李啊,這個文件你給我每50份一批給我送過來,我一併批閱!有時候咱們並不但願被觀察者有一絲的變化立刻就通知咱們,咱們能夠等被觀察者達到必定的程度的時候(好比說等溫度上升5℃之內沒必要通知系統,一旦超過5℃就通知系統!)再通知咱們,你能夠想一想這樣好處不少!因此當達到標準,咱們須要通知觀察者的時候調用setChanged()方法還真是不錯的哦!
b)關於觀察者
update的方法略有不一樣update(Observable o, Object arg),第一個參數是主題自己,第二個參數爲傳入notifyObserver()的數據對象,沒有爲空。這裏就來決定是由被觀察者push數據,仍是有觀察者本身pull數據。
代碼走起
1)被觀察者實現(注意import相應的package)
package my.oschina.net.design.observer.javautil; import java.util.Observable; import java.util.Observer; /** * 這種方式有一個弊端就是說Observable是一個 類而不是一個接口所以它限制了這個類的使用 * @author Eswin * */ public class WeatherData extends Observable{ //被觀測的指標數據 private float temp; private float humidity; private float pressure; public WeatherData(){} public void setStatus(float temp, float humidity, float pressure) { this.temp = temp; this.humidity = humidity; this.pressure = pressure; statusChanged(); } public void statusChanged() { setChanged(); notifyObservers(); } public float getTemp() { return temp; } public float getHumidity() { return humidity; } public float getPressure() { return pressure; } }
2)觀察者實現
package my.oschina.net.design.observer.javautil; import java.util.Observable; import java.util.Observer; import my.oschina.net.design.observer.owndesign.Display; public class CurrentConditionDisplay implements Observer, Display{ private float temp; private float humidity; private float pressure; private Observable observable; public CurrentConditionDisplay(Observable observable) { this.observable = observable; observable.addObserver(this); } @Override public void update(Observable o, Object arg) { // TODO Auto-generated method stub if(o instanceof WeatherData) { WeatherData weatherdata = (WeatherData)o; this.temp = weatherdata.getTemp(); this.humidity = weatherdata.getHumidity(); this.pressure = weatherdata.getPressure(); } display(); } @Override public void display() { // TODO Auto-generated method stub System.out.println("Temp --> " + temp + "humidity --> " +humidity + "pressure -->" + pressure); } }
3)Test一下
package my.oschina.net.design.observer.javautil; public class ObserverTest2 { public static void main(String[] args) { // TODO Auto-generated method stub WeatherData weatherdata = new WeatherData(); CurrentConditionDisplay cc = new CurrentConditionDisplay(weatherdata); weatherdata.setStatus(12, 12, 12); weatherdata.setStatus(13, 13, 13); weatherdata.setStatus(14, 14, 14); } }
4)結果截圖
模式延伸
其實咱們咱們在編程的過程當中有不少時候都運用到了觀察者模式,想一想Swing,還有JavaBean,還有RMI。
模式建議
1)要注意Observable這個類所帶來的問題;
2)有必要的話本身實現Observable也就是主題,很簡單(三個方法實現就能夠了)。