認識觀察者模式 首先來看看報紙訂閱的過程 1.報社的業務就是出版報紙 2.向某家報社訂閱報紙,只要他們有新報紙出版,就會送過來,只要你是他們的訂戶 3.當你不想再看報紙的時候,取消訂閱,他們就不會再送新報紙 4.只要報社還在運營,就會一直有人來訂閱或取消訂閱報紙 觀察者模式和報紙訂閱流程是一樣的,只 ...
認識觀察者模式
首先來看看報紙訂閱的過程
- 1.報社的業務就是出版報紙
- 2.向某家報社訂閱報紙,只要他們有新報紙出版,就會送過來,只要你是他們的訂戶
- 3.當你不想再看報紙的時候,取消訂閱,他們就不會再送新報紙
- 4.只要報社還在運營,就會一直有人來訂閱或取消訂閱報紙
觀察者模式和報紙訂閱流程是一樣的,只是名字不同。出版社改名為主題(Subject),而訂閱者改名為觀察者(Observer)
觀察者模式的定義
觀察者模式定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的所有依賴者都會受到通知並自動更新。
觀察者模式代碼
//主題介面
interface Subject {
void registerObserver(Observer o);//增加觀察者
void removeObserver(Observer o);//刪除觀察者
void notifyObservers();//當主題狀態改變時,調用此方法通知所有觀察者
}
//觀察者介面
interface Observer {
void update(float temp); //用來接收主題發送的通知,這裡假設主題是溫度計,通過介面給觀察者發送當前溫度
}
//主題實現
class Thermometer implements Subject {
private List<Observer> observers = new ArrayList<>();//觀察者集合
private float temp = 0.0f;//溫度
public void setTemp(float temp) {//溫度更新
this.temp = temp;
notifyObservers();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
if (observers.indexOf(o) >= 0)
observers.remove(o);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temp);
}
}
}
//觀察者實現
class ObserverA implements Observer {
@Override
public void update(float temp) {
System.out.println("觀察者A:當前的溫度是" + temp);
}
}
class ObserverB implements Observer {
@Override
public void update(float temp) {
System.out.println("觀察者B:當前的溫度是" + temp);
}
}
public class JavaApplication {
public static void main(String[] args) throws Exception{
//具體使用
Thermometer t = new Thermometer();
Observer a = new ObserverA();
Observer b = new ObserverB();
//為a,b註冊成為ts的觀察者
t.registerObserver(a);
t.registerObserver(b);
//更新溫度
t.setTemp(23.00f);
//a不再當觀察者
t.removeObserver(a);
//更新溫度
t.setTemp(24.00f);
}
}
另外,Java中已經內置了觀察者模式,在java.util包下有Observer介面和Observable類
和這裡的Subject介面和Observer介面很相似,修改後的代碼如下
//主題實現
class Thermometer extends Observable{
private float temp = 0.0f;//溫度
public void setTemp(float temp) {//溫度更新
this.temp = temp;
setChanged();//說明狀態已改變
notifyObservers(temp);
}
}
//觀察者實現
class ObserverA implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("觀察者A:當前的溫度是" + arg);
}
}
class ObserverB implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("觀察者B:當前的溫度是" + arg);
}
}
public class JavaApplication {
public static void main(String[] args) throws Exception{
//具體使用
Thermometer t = new Thermometer();
Observer a = new ObserverA();
Observer b = new ObserverB();
//為a,b註冊成為ts的觀察者
t.addObserver(a);
t.addObserver(b);
//更新溫度
t.setTemp(23.00f);
//a不再當觀察者
t.deleteObserver(a);
//更新溫度
t.setTemp(24.00f);
}
}
另外,既然JDK是開源的,那麼就順便去看看JDK的源碼中的具體實現
(這裡使用的源碼版本為jdk1.8.0_74)
Observable對象:(大部分沒什麼區別的代碼就不放出來了)
public Class Observable {
private boolean changed = false;
private Vector<Observer> obs;
...
}
私有成員變數,一個是標誌,用於後續判斷是否通知觀察者,一個觀察者集合obs,使用的是Vector容器
標誌的用途是用於增加自由度,比如說一秒鐘更新10次數據,對於前臺顯示而言可能不需要這麼頻繁,那麼我們可以自己計數,如果達到10次才設置標誌
可以在通知觀察者方法源碼里看到changed的作用
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();//clearChanged方法里的具體代碼就一句:changed = false;
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
而Observer介面更是沒什麼好說的
public interface Observer {
void update(Observable o, Object arg);
}
相對於我們自己實現的觀察者模式,主要區別在於將ArrayList換成了Vector,方法都加上了synchronized關鍵字來保證線程安全,並沒有什麼特別的← ←