http://jasonshieh.javaeye.com/blog/726557
package observe;
import java.util.Vector;
interface Observer {
public void update();
}
interface Subject {
public void attach(Observer o);
public void detach(Observer o);
public void notice();
}
class Teacher implements Subject {
private String phone;
private Vector students;
public Teacher() {
phone = "";
students = new Vector();
}
public void attach(Observer o) {
students.add(o);
}
public void detach(Observer o) {
students.remove(o);
}
public void notice() {
for (int i = 0; i < students.size(); i++)
((Observer) students.get(i)).update();
}
public void setPhone(String phone) {
this.phone = phone;
notice();
}
public String getPhone() {
return phone;
}
}
class Student implements Observer {
private String name;
private String phone;
private Teacher teacher;
public Student(String name, Teacher t) {
this.name = name;
teacher = t;
}
public void show() {
System.out.println("Name:" + name + "/nTeacher'sphone:" + phone);
}
public void update() {
phone = teacher.getPhone();
}
}
public class Client {
public static void main(String[] args) {
Vector students = new Vector();
Teacher t = new Teacher();
for (int i = 0; i < 5; i++) {
Student st = new Student("lili" + i, t);
students.add(st);
t.attach(st);
}
t.setPhone("88803807");
for (int i = 0; i < 5; i++)
((Student) students.get(i)).show();
}
觀察者模式可以參考郵件訂閱的例子
郵件訂閱設計到2個主要角色,一個是訂閱者(觀察者),一個是發行者
發行者可以擁有一個觀察者的集合,可以添加,刪除觀察者,當發行者發布一個新的訊息時,要郵件通知觀察者集合中的每一個。
所以,發行者實現的介面至少應具備三個方法,即註冊觀察者,登出觀察者,通知觀察者。
通知有兩種方式,一種是推(push),一種是拉(pull).
推,即發行者通過調用觀察者提供的介面,來通知觀察者一些變動(比如新增一個訊息)。
拉,即觀察者可以自主提取所要接受的資料,而不是全盤接受,主要體現在觀察者程式自己主動調用觀察者的傳值介面,而區別於推由發行者來調用,此時,需要這個介面中的參數包含發行者對象,讓程式知道掃描變動來自於哪個發行者。
JDK中內建了觀察者模式,位於java.util包中,一個介面Observer,一個類Observable,將這兩個類組合起來使用,既可以推,又可以拉。
一個普通的類,如果繼承了Observable,就成了一個發行者,實現了Observer介面,就成了觀察者。
JDK中的觀察者模式有一個弊端,就是發行者需要繼承一個類,而不是實現一個介面,如果需要成為發行者的類已經整合了一個類,就不能再繼承Observable了。這時候,就需要自己來設計一種觀察者模式了。
JDK 中Swing包中,大量運用了觀察者模式,所有的組件都繼承了JComponent,這就是一個發行者,它裡麵包含一個監聽器的集合:EventListenerList,使用者可以自訂一個監聽器,然後添加到一個組件中的時候,該組件就會把這個監聽器註冊到 EventListenerList中,相當於添加了一個發行者,當使用者對組件做出反應(如單擊)時,相關的監聽器(接受者)都會收到資訊並作出反應。
Observable提供必要的資訊.
Observer(Listener)則對Observer所提供的資料做自己感興趣的處理 .
比如TimeSource提供時間這一資料,TimeSink可以獲所得TimeSource提供的時間資料,有人可能要實現數字時鐘,另外有人可能想使用所提供的時間實現一個提醒服務。還有人可能想啟動每晚備份功能。簡而言之,希望一個單一的TimeSource對象能夠為多個TimeSink對象提供時間.
Observable與Observer關係,如果1 : 1則可以做成依賴關係, 如果1 : n 則在Observable 內儲存一個Observer的集合。
當然也可以利用第三個類來建立這二者的關係.Tomcat的Session與SessionListener就是利用第三個類建立二者的關係.
Observer的推模型和拉模型 。
推模型是通過把資料傳給 notify和update方法從而把資料從目標(subject)推給觀察者(observer).
拉模型沒有給notify和update方法傳遞任何資料,資料是在觀察者對象收到更新訊息後,查詢被觀察者對象得到的.
在資料量比較大時推模型更合適。
資料量比較小時拉模型比較合適.