觀察者模式:在該模式中,主要物件有觀察者和被觀察者,當被觀察者發生改變的時候,觀察者能夠得到更新通知,功能上聽起來有些像發布訂閱模式,但是與發布訂閱模式有很大的差異,發布者與訂閱者之間是有一個server的,之間的訊息會通過server進行通信,就像kafka、Redis之類的一樣;而在觀察者模式中,被觀察者會維護著一個串列,該串列保存著觀察者,當變化時,就直接對觀察者進行更新通知,所以更像是一種擁有并直接通知的關系,
![]()
在Java中,早在JDK1.0的版本就自帶了觀察者模式,提供了一個觀察者的介面和被觀察者實作類,UML類圖如下

Observer觀察者介面,實作了該觀察者介面的類在被觀察者發生改變的時候能夠被通知到,該介面定義了一個update方法,該方法會在被觀察者物件發生改變的時被呼叫,并且是在被觀察者
Observable物件的notifyObservers方法中呼叫,
package java.util;
/**
* A class can implement the <code>Observer</code> interface when it
* wants to be informed of changes in observable objects.
*
* @author Chris Warth
* @see java.util.Observable
* @since JDK1.0
*/
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}
接著來看被觀察者Observable,在被觀察者中維護著兩個屬性,一個布爾型別的changed,標識著被觀察者物件是否發生改變,發生改變則為true,默認false;一個是執行緒安全Vector容器串列obs,該容器中存放著觀察者,在構造方法中會對觀察者串列進行初始化,提供了對觀察者進行CURD的成員方法,addObserver添加觀察者,deleteObserver洗掉指定觀察者、deleteObservers洗掉所有觀察者、countObservers統計觀察者個數,這些成語方法都是被synchronized關鍵字修飾的,所以是執行緒安全的,對于changed,提供了setChanged和clearChanged兩個方法,setChanged方法會把changed置為true,clearChanged把changed置為false,也是執行緒安全的,通過方法notifyObservers對觀察者進行更新通知,
在檢測是否有變化以及獲取觀察者物件副本的時候會加上物件鎖,新加入的觀察者會得不到正在進行的變更通知,一個正在移除的觀察者可能會得到錯誤的通知,如果發生了改變,則獲取觀察者物件副本,并把變化標志置為false,然后逐一呼叫觀察者的update方法達到更新通知目的,
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
原始碼剖析之后,來看一個租客與房東的例子,作為一個擁有幾棟樓的房東,每個月需要做的事情就是通知他的租客交房租,日子就是那么樸實無華,
房東:
package design.observer;
import java.util.Calendar;
import java.util.Observable;
public class Landlady extends Observable {
public void notifyPay() {
this.setChanged();
Calendar cal = Calendar.getInstance();
int month = cal.get(Calendar.MONTH) + 1;
int year = cal.get(Calendar.YEAR);
Msg msg = new Msg(1, year + "年" + month + "月");
this.notifyObservers(msg);
}
}
租客:
package design.observer;
import com.alibaba.fastjson.JSON;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
public class Tenant implements Observer {
private String name;
public Tenant(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
Msg msg = (Msg) arg;
// System.out.println(JSON.toJSONString(msg));
// to 交房租
System.out.println(name + "交好了" +msg.desc+ "的房租");
}
}
測驗類:
package design.observer;
public class Test {
public static void main(String[] args) {
Landlady landlady = new Landlady();
landlady.addObserver(new Tenant("tom"));
landlady.addObserver(new Tenant("jerry"));
landlady.notifyPay();
}
}
運行結果:
![]()
UML類圖:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/271562.html
標籤:java
上一篇:Java實作多人聊天室
