利用Java提供的Observer接口和Observable類實(shí)現(xiàn)觀察者模式
對于觀察者模式休吠,其實(shí)Java已經(jīng)為我們提供了已有的接口和類谒获。對于訂閱者(Subscribe蛤肌,觀察者)Java為我們提供了一個(gè)接口,JDK源碼如下:
1 package java.util;
2
3 public interface Observer {
4 void update(Observable o, Object arg);
5 }
和我們上一篇實(shí)現(xiàn)的觀察者一樣批狱,僅提供一個(gè)update方法用于接收通知者的通知做出相應(yīng)改變寻定。
我們再來看看Java為我們提供了一個(gè)怎樣的通知者(Publish,發(fā)布者)精耐,JDK源碼如下:
package java.util;
public class Observable {
private boolean changed = false; //是否改變狀態(tài)
private Vector obs; //Vector利用同步方法來線程安全狼速,線程安全在多線程情況下不會造成數(shù)據(jù)混亂
public Observable() {
obs = new Vector();
}
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed) //狀態(tài)值未改變時(shí)返回,不通知
return;
arrLocal = obs.toArray(); //將Vector轉(zhuǎn)換成數(shù)組
clearChanged(); //重置狀態(tài)
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
不得不說卦停,Java源碼考慮得就是比自己寫的要好向胡。首先,使用Vector惊完,Vector相比于ArrayList來說僵芹,它是線程安全的。其次小槐,在添加和刪除觀察者時(shí)對兩個(gè)方法使用了synchronized關(guān)鍵字拇派,這都是在為多線程考慮。確實(shí)Java源碼并不是那么可怕凿跳,它同樣也是由一些最簡單最基礎(chǔ)的組合而來件豌。
接下來我們來看看是如何利用Java提供的接口和方法來實(shí)現(xiàn)觀察者模式。
package day_10_observer_jdk;
import java.util.Observable;
import java.util.Observer;
/**
* 實(shí)現(xiàn)java.util.Observer接口的觀察者
* @author turbo
*
* 2016年9月14日
*/
public class Subscribe implements Observer {
public Subscribe(Observable o){
o.addObserver(this); //將該觀察者放入待通知觀察者里
}
/* (non-Javadoc)
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
@Override
public void update(Observable o, Object arg) {
System.out.println("收到通知:" + ((Publish)o).getData());
}
}
package day_10_observer_jdk;
import java.util.Observable;
/**
* 繼承java.util.Observable的通知者
* @author turbo
*
* 2016年9月14日
*/
public class Publish extends Observable {
private String data = "";
public String getData() {
return data;
}
public void setData(String data) {
if (!this.data.equals(data)){
this.data = data;
setChanged(); //改變通知者的狀態(tài)
}
notifyObservers(); //調(diào)用父類Observable方法控嗜,通知所有觀察者
}
}
客戶端測試代碼:
package day_10_observer_jdk;
/**
* @author turbo
*
* 2016年9月14日
*/
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
Publish publish = new Publish();
Subscribe subscribe = new Subscribe(publish);
publish.setData("開始");
}
}
這樣我們就利用了Java給我們提供的Observer接口和Observable類實(shí)現(xiàn)了觀察者模式茧彤。上一篇我們提到了事件委托,我們在下一篇來了解一下什么是事件委托疆栏。